From 048da03e9e84ae936526b77729420dfe84160635 Mon Sep 17 00:00:00 2001 From: Madhur Gupta Date: Tue, 13 Jan 2026 22:04:28 +0530 Subject: [PATCH 1/9] refactor(frontend): update block time tracker components for improved execution time visualization --- .../block-time-tracker/block-time-legend.tsx | 31 +--- .../block-time-timeline.tsx | 16 +- .../block-time-tracker/block-time.tsx | 160 +++++++++++------- .../components/block-time-tracker/index.tsx | 13 +- frontend/hooks/use-block-tracker.ts | 33 ++-- frontend/lib/block-metrics.ts | 83 ++++----- 6 files changed, 186 insertions(+), 150 deletions(-) diff --git a/frontend/components/block-time-tracker/block-time-legend.tsx b/frontend/components/block-time-tracker/block-time-legend.tsx index 0185c92..d6feb9c 100644 --- a/frontend/components/block-time-tracker/block-time-legend.tsx +++ b/frontend/components/block-time-tracker/block-time-legend.tsx @@ -4,37 +4,24 @@ export const BlockTimeLegend = () => { return (
- +
- Height = execution time + Bar height reflects execution time. - Purple glow = concurrent transactions observed + Factor = total tx exec time / block exec time.
-
-

Block Execution Time

-

Block Exec. Time

+
+

Block execution time

+

Block

-
-
-
-

Transaction Execution Time

-

Tx Exec. Time

-
-
-
-

Parallel Execution

-

Parallel Exec.

+
+

Total tx execution time

+

Tx exec

diff --git a/frontend/components/block-time-tracker/block-time-timeline.tsx b/frontend/components/block-time-tracker/block-time-timeline.tsx index b877088..b42ff36 100644 --- a/frontend/components/block-time-tracker/block-time-timeline.tsx +++ b/frontend/components/block-time-tracker/block-time-timeline.tsx @@ -8,8 +8,8 @@ import type { Block } from '@/types/block' import { BlockTime } from './block-time' const BLOCK_DIMENSIONS = { - small: { itemWidth: 120, gridHeight: 280 }, - large: { itemWidth: 140, gridHeight: 280 }, + small: { itemWidth: 150, gridHeight: 280 }, + large: { itemWidth: 180, gridHeight: 280 }, } const getResponsiveDimensions = () => { @@ -27,19 +27,19 @@ const getResponsiveDimensions = () => { interface BlockTimeTimelineProps { blocks: Block[] isFollowingChain: boolean - normalizedBlockExecutionTime: number + normalizedTimeScaleMs: number } interface BlockCellData { blocks: Block[] - normalizedBlockExecutionTime: number + normalizedTimeScaleMs: number } function BlockCell({ columnIndex, style, blocks, - normalizedBlockExecutionTime, + normalizedTimeScaleMs, }: CellComponentProps) { const block = blocks[columnIndex] @@ -47,7 +47,7 @@ function BlockCell({
) @@ -61,7 +61,7 @@ function BlockCell({ export function BlockTimeTimeline({ blocks, isFollowingChain, - normalizedBlockExecutionTime, + normalizedTimeScaleMs, }: BlockTimeTimelineProps) { const containerRef = useRef(null) const [containerWidth, setContainerWidth] = useState(0) @@ -117,7 +117,7 @@ export function BlockTimeTimeline({ defaultWidth={containerWidth} overscanCount={3} cellComponent={BlockCell} - cellProps={{ blocks: sortedBlocks, normalizedBlockExecutionTime }} + cellProps={{ blocks: sortedBlocks, normalizedTimeScaleMs }} className="scrollbar-none" style={{ overflowX: isFollowingChain ? 'hidden' : 'auto', diff --git a/frontend/components/block-time-tracker/block-time.tsx b/frontend/components/block-time-tracker/block-time.tsx index ae927e2..b1e5b69 100644 --- a/frontend/components/block-time-tracker/block-time.tsx +++ b/frontend/components/block-time-tracker/block-time.tsx @@ -6,7 +6,8 @@ import { TooltipTrigger, } from '@/components/ui/tooltip' import { EXPLORER_URL } from '@/constants/common' -import { calculateBarMetrics, fromNsToMsPrecise } from '@/lib/block-metrics' +import { PARALLEL_EXECUTION_RATIO_THRESHOLD } from '@/hooks/use-block-tracker' +import { calculateBarMetrics } from '@/lib/block-metrics' import { formatBlockNumber } from '@/lib/ui' import { cn } from '@/lib/utils' import type { Block } from '@/types/block' @@ -14,72 +15,68 @@ import { ExternalLink } from '../ui/external-link' interface BlockTimeProps { block: Block - normalizedBlockExecutionTime: number + normalizedTimeScaleMs: number } -export const BlockTime = ({ - block, - normalizedBlockExecutionTime, -}: BlockTimeProps) => { +export const BlockTime = ({ block, normalizedTimeScaleMs }: BlockTimeProps) => { const { - barHeightPercentage, - fillPercentage, + blockHeightPct, + txHeightPct, + blockMs, totalTransactionTime, - isHighlyParallel, + isParallelExecution, + parallelizationRatio, + timeSavedMs, } = useMemo( - () => calculateBarMetrics(block, normalizedBlockExecutionTime), - [block, normalizedBlockExecutionTime], + () => + calculateBarMetrics( + block, + normalizedTimeScaleMs, + PARALLEL_EXECUTION_RATIO_THRESHOLD, + ), + [block, normalizedTimeScaleMs], ) - const formattedBlockExecutionTime = fromNsToMsPrecise( - block.executionTime ?? BigInt(0), - ).toFixed(3) + const formattedBlockExecutionTime = blockMs.toFixed(3) const formattedTotalTransactionTime = totalTransactionTime.toFixed(3) const numberOfTransactions = (block.transactions ?? []).length - const parallelPercentage = isHighlyParallel - ? (Number(formattedTotalTransactionTime) * 100) / - Number(formattedBlockExecutionTime) - - 100 - : 0 // Compute actual percentage of difference tx time and execution between block - const timeSaved = - Number(formattedTotalTransactionTime) - Number(formattedBlockExecutionTime) + const parallelRatioLabel = `${parallelizationRatio.toFixed(2)}×` + const timeSaved = timeSavedMs return ( -
+
{/* Block Bar Container */} -
- {/* Block Time Container (represents total block execution time) */} +
+ {/* Dual bar comparison (Block exec time vs total tx exec time) */} - - {/* Transaction Time Fill */} - + +

- Block Execution Time + Block execution time

{formattedBlockExecutionTime}ms @@ -104,7 +101,7 @@ export const BlockTime = ({

- Transaction Execution Time + Total tx execution time

{formattedTotalTransactionTime}ms @@ -120,30 +117,37 @@ export const BlockTime = ({

- Time Saved + Time saved

- {timeSaved < 0 ? 0 : timeSaved.toFixed(3)} - ms + {timeSaved.toFixed(3)}ms

- Parallel Efficiency + Parallel factor

-

- {parallelPercentage.toFixed(3)}% +

+ {parallelRatioLabel}

- {isHighlyParallel && ( + {isParallelExecution && (

- High parallel execution detected + Parallel execution: total tx execution time > block + execution time

@@ -154,19 +158,51 @@ export const BlockTime = ({
{/* Block Stats */} -
-

- {formattedBlockExecutionTime}ms -

-

{numberOfTransactions} tx

+
+
+
+ + Block + + + {blockMs.toFixed(2)}ms + +
+
+ + Tx exec + + + {totalTransactionTime.toFixed(2)}ms + +
+
+ +
+ + {isParallelExecution + ? `Parallel ${parallelRatioLabel}` + : `Factor ${parallelRatioLabel}`} + +
{/* Separator */}
{/* Block number Label */} -
- {formatBlockNumber(block.number)} +
+
+ {formatBlockNumber(block.number)} +
) diff --git a/frontend/components/block-time-tracker/index.tsx b/frontend/components/block-time-tracker/index.tsx index d547a0d..7e29a82 100644 --- a/frontend/components/block-time-tracker/index.tsx +++ b/frontend/components/block-time-tracker/index.tsx @@ -22,11 +22,8 @@ import { BlockTimeTimeline } from './block-time-timeline' * and calculates execution timing metrics for visualization. */ export function BlockTimeExecutionTracker() { - const { - finalizedBlocks, - maxBlockExecutionTime, - normalizedBlockExecutionTime, - } = useBlockTracker() + const { finalizedBlocks, maxBlockExecutionTime, normalizedTimeScaleMs } = + useBlockTracker() const [isFollowingChain, setIsFollowingChain] = useState(true) const { isHovering, hoverProps } = useMouseHover() const isPaused = !isFollowingChain || isHovering @@ -80,7 +77,7 @@ export function BlockTimeExecutionTracker() {
-
+
{/* Scrollable Blocks Container */} diff --git a/frontend/hooks/use-block-tracker.ts b/frontend/hooks/use-block-tracker.ts index e00e328..0b83c34 100644 --- a/frontend/hooks/use-block-tracker.ts +++ b/frontend/hooks/use-block-tracker.ts @@ -1,11 +1,19 @@ import { useCallback, useMemo, useState } from 'react' -import { fromNsToMsPrecise } from '@/lib/block-metrics' +import { + fromNsToMsPrecise, + getBlockWallTimeMs, + getTotalTransactionTimeMs, +} from '@/lib/block-metrics' import type { Block } from '@/types/block' import type { SerializableEventData } from '@/types/events' import { useEvents } from './use-events' const MAX_BLOCKS = 5000 +// Highlight when total tx execution time exceeds block execution time. +// Keep this as a single constant so UI/copy can stay consistent. +export const PARALLEL_EXECUTION_RATIO_THRESHOLD = 1 + /** * Custom hook to track block execution events and manage block state * @returns Object containing blocks state and calculated metrics @@ -268,22 +276,25 @@ export function useBlockTracker() { ) }, [finalizedBlocks]) - const normalizedBlockExecutionTime = useMemo(() => { + const normalizedTimeScaleMs = useMemo(() => { if (finalizedBlocks.length === 0) return 1 - // Get all execution times in milliseconds - const executionTimes = finalizedBlocks - .map((block) => fromNsToMsPrecise(block.executionTime ?? BigInt(0))) + // Normalize against the larger of: + // - block wall-time (BlockEnd - BlockStart) + // - ΣTx execution time (sum of TxnHeaderEnd - TxnHeaderStart) + // This lets the visualization show when ΣTx > block time (parallel overlap). + const maxTimes = finalizedBlocks + .map((block) => + Math.max(getBlockWallTimeMs(block), getTotalTransactionTimeMs(block)), + ) .filter((time) => time > 0) .sort((a, b) => a - b) - if (executionTimes.length === 0) return 1 + if (maxTimes.length === 0) return 1 // Use 95th percentile to be resistant to spikes - const percentileIndex = Math.floor(executionTimes.length * 0.95) - const percentile95 = - executionTimes[percentileIndex] || - executionTimes[executionTimes.length - 1] + const percentileIndex = Math.floor(maxTimes.length * 0.95) + const percentile95 = maxTimes[percentileIndex] || maxTimes[maxTimes.length - 1] // Add 10% buffer to prevent clipping of high values near the percentile return percentile95 * 1.1 @@ -293,6 +304,6 @@ export function useBlockTracker() { blocks, finalizedBlocks, maxBlockExecutionTime, - normalizedBlockExecutionTime, + normalizedTimeScaleMs, } } diff --git a/frontend/lib/block-metrics.ts b/frontend/lib/block-metrics.ts index 87e1671..b0fff82 100644 --- a/frontend/lib/block-metrics.ts +++ b/frontend/lib/block-metrics.ts @@ -12,58 +12,63 @@ export function fromNsToMsPrecise(ns: bigint): number { return msPart + nsPart / 1_000_000 } +function sumTransactionTimeNs(block: Block): bigint { + return (block.transactions ?? []).reduce( + (sum, tx) => sum + BigInt(tx.transactionTime ?? 0), + BigInt(0), + ) +} + +export function getBlockWallTimeMs(block: Block): number { + return fromNsToMsPrecise(block.executionTime ?? BigInt(0)) +} + +export function getTotalTransactionTimeMs(block: Block): number { + return fromNsToMsPrecise(sumTransactionTimeNs(block)) +} + +export function getParallelizationRatio(blockMs: number, totalTxMs: number): number { + if (!(blockMs > 0)) return 0 + const ratio = totalTxMs / blockMs + return Number.isFinite(ratio) ? ratio : 0 +} + +export function getTimeSavedMs(blockMs: number, totalTxMs: number): number { + return Math.max(totalTxMs - blockMs, 0) +} + /** * Calculate bar metrics for a block visualization * @param block - The block to calculate metrics for - * @param maxBlockExecutionTime - The maximum block execution time in the dataset for normalization - * @returns Object containing bar height percentage and fill percentage + * @param normalizedTimeScaleMs - Shared normalization scale for both bars (ms) + * @returns Object containing bar height percentages and tooltip metrics */ export function calculateBarMetrics( block: Block, - maxBlockExecutionTime: number, + normalizedTimeScaleMs: number, + parallelExecutionRatioThreshold: number, ) { - const blockExecutionTime = block.executionTime ?? BigInt(0) - - // Calculate total transaction execution time with high precision - const totalTransactionTimeNs = (block.transactions ?? []).reduce( - (sum, tx) => sum + BigInt(tx.transactionTime ?? 0), - BigInt(0), - ) - const totalTransactionTime = fromNsToMsPrecise(totalTransactionTimeNs) + const blockMs = getBlockWallTimeMs(block) + const totalTransactionTime = getTotalTransactionTimeMs(block) + const parallelizationRatio = getParallelizationRatio(blockMs, totalTransactionTime) + const isParallelExecution = parallelizationRatio > parallelExecutionRatioThreshold - // Normalize bar height based on block time (container represents block execution time) - // If no execution time, show minimal height for blocks that exist - const barHeightPercentage = - Number(blockExecutionTime) > 0 - ? (fromNsToMsPrecise(blockExecutionTime) / maxBlockExecutionTime) * 100 - : 20 // Show something for blocks without execution time yet + const timeSavedMs = getTimeSavedMs(blockMs, totalTransactionTime) - // Calculate fill percentage (transaction time relative to block time) - // If transactions run in parallel, total transaction time can be > block time - // But the fill can't exceed 100% of the container - const fillPercentage = - Number(blockExecutionTime) > 0 - ? Math.min( - (totalTransactionTime / fromNsToMsPrecise(blockExecutionTime)) * 100, - 100, - ) - : totalTransactionTime > 0 - ? 50 - : 0 // Show some fill if we have transactions + const scaleMs = normalizedTimeScaleMs > 0 ? normalizedTimeScaleMs : 1 - // Calculate efficiency metrics - const parallelizationRatio = - Number(blockExecutionTime) > 0 - ? totalTransactionTime / fromNsToMsPrecise(blockExecutionTime) - : 0 - const isHighlyParallel = - parallelizationRatio > 1 && Number.isFinite(parallelizationRatio) + // Normalize both bars using the same scale so that ΣTx can exceed block time. + // If no execution time yet, show a minimal visible placeholder. + const blockHeightPct = blockMs > 0 ? (blockMs / scaleMs) * 100 : 20 + const txHeightPct = totalTransactionTime > 0 ? (totalTransactionTime / scaleMs) * 100 : 0 return { - barHeightPercentage: Math.max(barHeightPercentage * 0.8, 15), // Ensure minimum height - fillPercentage, + blockHeightPct: Math.max(Math.min(blockHeightPct, 100) * 0.9, 15), // Ensure minimum height + a little headroom + txHeightPct: Math.min(txHeightPct, 100) * 0.9, + blockMs, totalTransactionTime, parallelizationRatio, - isHighlyParallel, + isParallelExecution, + timeSavedMs, } } From 2532a10b0a414d459faa39eaa340e816b8d04cd3 Mon Sep 17 00:00:00 2001 From: Madhur Gupta Date: Tue, 13 Jan 2026 22:11:16 +0530 Subject: [PATCH 2/9] fix(frontend): update description in BlockTimeExecutionTracker for clarity on execution time visualization --- frontend/components/block-time-tracker/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/block-time-tracker/index.tsx b/frontend/components/block-time-tracker/index.tsx index 7e29a82..353f559 100644 --- a/frontend/components/block-time-tracker/index.tsx +++ b/frontend/components/block-time-tracker/index.tsx @@ -77,7 +77,7 @@ export function BlockTimeExecutionTracker() {
- -
- -
- {BLOCK_STATE_LEGEND.map((item) => ( -
-
- - {item.label} + {/* Desktop hover pause info */} +
+ + + Hovering on the Block stream pauses the update.
- ))} -
- - {/* Info copy - only for mobile */} -
- - Tap Pause to freeze and scroll through blocks -
- - - - {/* Info copy - only for desktop */} -
- - Hover to pause +
) diff --git a/frontend/components/block-time-tracker/block-time-legend.tsx b/frontend/components/block-time-tracker/block-time-legend.tsx index d6feb9c..5b4926a 100644 --- a/frontend/components/block-time-tracker/block-time-legend.tsx +++ b/frontend/components/block-time-tracker/block-time-legend.tsx @@ -1,28 +1,15 @@ -import { Info } from 'lucide-react' - export const BlockTimeLegend = () => { return ( -
-
- -
- Bar height reflects execution time. - - Factor = total tx exec time / block exec time. - -
+
+
+
+ Block execution time
-
-
-
-

Block execution time

-

Block

-
-
-
-

Total tx execution time

-

Tx exec

-
+
+
+ + Total transaction execution +
) diff --git a/frontend/components/block-time-tracker/block-time-timeline.tsx b/frontend/components/block-time-tracker/block-time-timeline.tsx index 2fa3223..2b0444c 100644 --- a/frontend/components/block-time-tracker/block-time-timeline.tsx +++ b/frontend/components/block-time-tracker/block-time-timeline.tsx @@ -8,8 +8,8 @@ import type { Block } from '@/types/block' import { BlockTime } from './block-time' const BLOCK_DIMENSIONS = { - small: { itemWidth: 150, gridHeight: 280 }, - large: { itemWidth: 180, gridHeight: 280 }, + small: { itemWidth: 180, gridHeight: 340 }, + large: { itemWidth: 220, gridHeight: 340 }, } const getResponsiveDimensions = () => { @@ -108,9 +108,9 @@ export function BlockTimeTimeline({ }, [isFollowingChain]) return ( -
+
{sortedBlocks.length === 0 ? ( -
+
) : ( diff --git a/frontend/components/block-time-tracker/block-time.tsx b/frontend/components/block-time-tracker/block-time.tsx index 1bd24b0..779fb11 100644 --- a/frontend/components/block-time-tracker/block-time.tsx +++ b/frontend/components/block-time-tracker/block-time.tsx @@ -11,22 +11,24 @@ import { calculateBarMetrics } from '@/lib/block-metrics' import { formatBlockNumber } from '@/lib/ui' import { cn } from '@/lib/utils' import type { Block } from '@/types/block' -import { ExternalLink } from '../ui/external-link' interface BlockTimeProps { block: Block normalizedTimeScaleMs: number } +const BAR_CONTAINER_HEIGHT = 200 + export const BlockTime = ({ block, normalizedTimeScaleMs }: BlockTimeProps) => { const { blockHeightPct, txHeightPct, blockMs, totalTransactionTime, - isParallelExecution, parallelizationRatio, + isParallelExecution, timeSavedMs, + parallelEfficiencyPct, } = useMemo( () => calculateBarMetrics( @@ -37,174 +39,149 @@ export const BlockTime = ({ block, normalizedTimeScaleMs }: BlockTimeProps) => { [block, normalizedTimeScaleMs], ) - const formattedBlockExecutionTime = blockMs.toFixed(3) - const formattedTotalTransactionTime = totalTransactionTime.toFixed(3) + const formattedBlockExecutionTime = blockMs.toFixed(2) + const formattedTotalTransactionTime = totalTransactionTime.toFixed(2) const numberOfTransactions = (block.transactions ?? []).length const parallelRatioLabel = `${parallelizationRatio.toFixed(2)}×` const timeSaved = timeSavedMs return ( -
- {/* Block Bar Container */} -
- {/* Dual bar comparison (Block exec time vs total tx exec time) */} - - -
+
+ {/* Bar chart area */} + + +
+ {/* Block execution bar (cyan) - overlaps right bar */} +
+ + {formattedBlockExecutionTime}ms + +
+ + {/* Tx execution bar (purple) */} +
+ + {formattedTotalTransactionTime}ms +
- - -
+
+ + + {/* Tooltip content */} + +
+ {/* Tooltip header */} +
+ + Block {formatBlockNumber(block.number)} + + + {/* Stats rows */}
- - Block {formatBlockNumber(block.number)} - -
-
-

- Block execution time -

-

- {formattedBlockExecutionTime}ms -

-
-
-

- Total tx execution time -

-

- {formattedTotalTransactionTime}ms -

-
-
-

- Transactions -

-

- {numberOfTransactions} -

-
-
-

- Time saved -

-

- {timeSaved.toFixed(3)}ms -

-
-
-

- Parallel factor -

-

- {parallelRatioLabel} -

-
+
+ + Block execution time: + + + {formattedBlockExecutionTime}ms +
-
- {isParallelExecution && ( -
-
-
-
-

- Parallel execution: total tx execution time > block - execution time -

-
+
+ + Transaction execution time: + + + {formattedTotalTransactionTime}ms +
- )} +
+ + Transactions: + + + {numberOfTransactions} + +
+
+ + Time Saved + + + {timeSaved.toFixed(2)}ms + +
+
+ + Parallel Efficiency: + + + {parallelEfficiencyPct.toFixed(2)}% + +
+
- - -
- {/* Block Stats */} -
-
-
- - Block - - - {blockMs.toFixed(2)}ms - -
-
- - Tx exec - - - {totalTransactionTime.toFixed(2)}ms - + {/* Tooltip footer */} +
+ + {numberOfTransactions} tx{numberOfTransactions !== 1 ? 's' : ''} + + + View on explorer + +
-
+ + -
- - {isParallelExecution - ? `Parallel ${parallelRatioLabel}` - : `Factor ${parallelRatioLabel}`} - -
+ {/* Block info below bars */} +
+ + {formatBlockNumber(block.number)} + + + Parallel {parallelRatioLabel} +
- - {/* Separator */} -
- - {/* Block number Label */} - - {formatBlockNumber(block.number)} -
) } diff --git a/frontend/components/block-time-tracker/index.tsx b/frontend/components/block-time-tracker/index.tsx index 947c776..d7edcd4 100644 --- a/frontend/components/block-time-tracker/index.tsx +++ b/frontend/components/block-time-tracker/index.tsx @@ -77,13 +77,13 @@ export function BlockTimeExecutionTracker() {
- {/* Main container - no rounded corners, borders carry across */} -
+ {/* Main container - only vertical (left/right) borders */} +
{/* Legend bar */} -
+
@@ -100,27 +100,29 @@ export function BlockTimeExecutionTracker() {
{/* Footer with hover pause info (desktop) and pause button (mobile) */} -
- {/* Mobile pause/resume button */} - +
+
+ {/* Mobile pause/resume button */} + - {/* Desktop hover pause info */} -
- - - Hovering on the Block stream pauses the update. - + {/* Desktop hover pause info */} +
+ + + Hovering on the Block stream pauses the update. + +
diff --git a/frontend/components/swap-transfer-tracker/index.tsx b/frontend/components/swap-transfer-tracker/index.tsx index 10f0e5e..3ffb361 100644 --- a/frontend/components/swap-transfer-tracker/index.tsx +++ b/frontend/components/swap-transfer-tracker/index.tsx @@ -1,6 +1,6 @@ 'use client' -import { ArrowLeftRight, Info, Pause, Play, Send } from 'lucide-react' +import { ArrowLeftRight, Pointer, Send } from 'lucide-react' import { useState } from 'react' import { LiveBadge } from '@/components/common/live-badge' import { SectionHeader } from '@/components/ui/section-header' @@ -30,37 +30,13 @@ export function SwapTransferTracker() { const [isFollowingData, setIsFollowingData] = useState(true) return ( -
+
- - + title="Live Transaction Log" + description="Real-time swaps and transfers observed directly from execution events." + /> - {/* Info copy - only for mobile */} -
- - Tap Pause to freeze and scroll through data -
- -
+
@@ -97,12 +73,31 @@ export function SwapTransferTracker() { /> -
- {/* Info copy - only for desktop */} -
- - Hover to pause + {/* Footer with hover pause info */} +
+ {/* Mobile pause/resume button */} + + + {/* Desktop hover pause info */} +
+ + + Hovering on the data stream pauses the update. + +
+
) diff --git a/frontend/components/ui/section-header.tsx b/frontend/components/ui/section-header.tsx index 110e7f9..17fd4d5 100644 --- a/frontend/components/ui/section-header.tsx +++ b/frontend/components/ui/section-header.tsx @@ -2,12 +2,13 @@ import type { ReactNode } from 'react' interface SectionHeaderProps { title: string - description: string | ReactNode + description?: string | ReactNode | null children?: ReactNode } /** * Section header with title and description, optional action area + * Horizontal layout with border on desktop, stacked on mobile */ export function SectionHeader({ title, @@ -15,15 +16,17 @@ export function SectionHeader({ children, }: SectionHeaderProps) { return ( -
-
-

- {title} -

-
- {description} -
+
+
+ {title}
+ {description && ( +
+
+ {description} +
+
+ )} {children}
) diff --git a/frontend/components/ui/switch.tsx b/frontend/components/ui/switch.tsx index 72402c9..197edd5 100644 --- a/frontend/components/ui/switch.tsx +++ b/frontend/components/ui/switch.tsx @@ -13,7 +13,8 @@ function Switch({ diff --git a/frontend/lib/block-metrics.ts b/frontend/lib/block-metrics.ts index cfb7dcc..c54c16f 100644 --- a/frontend/lib/block-metrics.ts +++ b/frontend/lib/block-metrics.ts @@ -70,6 +70,10 @@ export function calculateBarMetrics( const txHeightPct = totalTransactionTime > 0 ? (totalTransactionTime / scaleMs) * 100 : 0 + // Calculate parallel efficiency as percentage + const parallelEfficiencyPct = + totalTransactionTime > 0 ? (timeSavedMs / totalTransactionTime) * 100 : 0 + return { blockHeightPct: Math.max(Math.min(blockHeightPct, 100) * 0.9, 15), // Ensure minimum height + a little headroom txHeightPct: Math.min(txHeightPct, 100) * 0.9, @@ -78,5 +82,6 @@ export function calculateBarMetrics( parallelizationRatio, isParallelExecution, timeSavedMs, + parallelEfficiencyPct, } } From d6d21498d70e1036b35a25ae40ee99fd5163fb57 Mon Sep 17 00:00:00 2001 From: Madhur Gupta Date: Fri, 16 Jan 2026 22:30:47 +0530 Subject: [PATCH 7/9] refactor(frontend): improve layout structure with continuous borders and responsive spacing --- frontend/app/page.tsx | 15 +- .../components/block-state-tracker/index.tsx | 2 +- .../block-time-timeline.tsx | 4 +- .../block-time-tracker/block-time.tsx | 219 +++++++++--------- .../components/block-time-tracker/index.tsx | 60 ++--- .../swap-transfer-tracker/index.tsx | 2 +- frontend/components/ui/button.tsx | 55 +++++ frontend/components/ui/section-header.tsx | 18 +- 8 files changed, 227 insertions(+), 148 deletions(-) create mode 100644 frontend/components/ui/button.tsx diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx index f606ddc..98455c5 100644 --- a/frontend/app/page.tsx +++ b/frontend/app/page.tsx @@ -9,18 +9,21 @@ import { SwapTransferTracker } from '@/components/swap-transfer-tracker' export default function Home() { return (
-
+
- + {/* Sections container with continuous left/right borders */} +
+ - + - + - + +
-
+
diff --git a/frontend/components/block-state-tracker/index.tsx b/frontend/components/block-state-tracker/index.tsx index 371880e..3abfa1c 100644 --- a/frontend/components/block-state-tracker/index.tsx +++ b/frontend/components/block-state-tracker/index.tsx @@ -46,7 +46,7 @@ export function BlockStateTracker() { /> {/* Main container - no rounded corners */} -
+
{/* Legend bar with slow mode toggle */}
diff --git a/frontend/components/block-time-tracker/block-time-timeline.tsx b/frontend/components/block-time-tracker/block-time-timeline.tsx index 2b0444c..2477e03 100644 --- a/frontend/components/block-time-tracker/block-time-timeline.tsx +++ b/frontend/components/block-time-tracker/block-time-timeline.tsx @@ -108,9 +108,9 @@ export function BlockTimeTimeline({ }, [isFollowingChain]) return ( -
+
{sortedBlocks.length === 0 ? ( -
+
) : ( diff --git a/frontend/components/block-time-tracker/block-time.tsx b/frontend/components/block-time-tracker/block-time.tsx index 779fb11..987359a 100644 --- a/frontend/components/block-time-tracker/block-time.tsx +++ b/frontend/components/block-time-tracker/block-time.tsx @@ -46,120 +46,129 @@ export const BlockTime = ({ block, normalizedTimeScaleMs }: BlockTimeProps) => { const timeSaved = timeSavedMs return ( -
+
{/* Bar chart area */} - - -
- {/* Block execution bar (cyan) - overlaps right bar */} -
- - {formattedBlockExecutionTime}ms - - -
+
+ + +
+ {/* Left bar column (cyan) - label + bar */} +
+ + {formattedBlockExecutionTime}ms + + +
- {/* Tx execution bar (purple) */} -
- - {formattedTotalTransactionTime}ms - - + {/* Right bar column (purple) - label + bar */} +
+ + {formattedTotalTransactionTime}ms + + +
-
-
+ - {/* Tooltip content */} - -
- {/* Tooltip header */} -
- - Block {formatBlockNumber(block.number)} - + {/* Tooltip content */} + +
+ {/* Tooltip header */} +
+ + Block {formatBlockNumber(block.number)} + - {/* Stats rows */} -
-
- - Block execution time: - - - {formattedBlockExecutionTime}ms - -
-
- - Transaction execution time: - - - {formattedTotalTransactionTime}ms - -
-
- - Transactions: - - - {numberOfTransactions} - -
-
- - Time Saved - - - {timeSaved.toFixed(2)}ms - -
-
- - Parallel Efficiency: - - - {parallelEfficiencyPct.toFixed(2)}% - + {/* Stats rows */} +
+
+ + Block execution time: + + + {formattedBlockExecutionTime}ms + +
+
+ + Transaction execution time: + + + {formattedTotalTransactionTime}ms + +
+
+ + Transactions: + + + {numberOfTransactions} + +
+
+ + Time Saved + + + {timeSaved.toFixed(2)}ms + +
+
+ + Parallel Efficiency: + + + {parallelEfficiencyPct.toFixed(2)}% + +
-
- {/* Tooltip footer */} -
- - {numberOfTransactions} tx{numberOfTransactions !== 1 ? 's' : ''} - - - View on explorer - + {/* Tooltip footer */} +
+ + {numberOfTransactions} tx + {numberOfTransactions !== 1 ? 's' : ''} + + + View on explorer + +
-
- - + + +
{/* Block info below bars */}
diff --git a/frontend/components/block-time-tracker/index.tsx b/frontend/components/block-time-tracker/index.tsx index d7edcd4..c5cd90a 100644 --- a/frontend/components/block-time-tracker/index.tsx +++ b/frontend/components/block-time-tracker/index.tsx @@ -77,20 +77,41 @@ export function BlockTimeExecutionTracker() {
- {/* Main container - only vertical (left/right) borders */} -
+ {/* Mobile pause/resume button - below section header */} +
+ + + {isFollowingChain + ? 'Pause to freeze and scroll' + : 'Resume to follow chain'} + +
+ + {/* Main container */} +
{/* Legend bar */}
{/* Blocks timeline area */} -
+
{/* Left fade gradient - only on sm and above */} -
+
- {/* Footer with hover pause info (desktop) and pause button (mobile) */} -
+ {/* Footer with hover pause info - desktop only */} +
- {/* Mobile pause/resume button */} - - - {/* Desktop hover pause info */} -
- - - Hovering on the Block stream pauses the update. - -
+ + + Hovering on the Block stream pauses the update. +
diff --git a/frontend/components/swap-transfer-tracker/index.tsx b/frontend/components/swap-transfer-tracker/index.tsx index 3ffb361..dddee04 100644 --- a/frontend/components/swap-transfer-tracker/index.tsx +++ b/frontend/components/swap-transfer-tracker/index.tsx @@ -36,7 +36,7 @@ export function SwapTransferTracker() { description="Real-time swaps and transfers observed directly from execution events." /> -
+
diff --git a/frontend/components/ui/button.tsx b/frontend/components/ui/button.tsx new file mode 100644 index 0000000..aaf3256 --- /dev/null +++ b/frontend/components/ui/button.tsx @@ -0,0 +1,55 @@ +import { cva, type VariantProps } from 'class-variance-authority' +import { forwardRef } from 'react' +import { cn } from '@/lib/utils' + +const buttonVariants = cva( + 'inline-flex items-center justify-center font-mono text-sm uppercase cursor-pointer transition-all duration-200 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + primary: [ + 'rounded-md text-white', + 'bg-[radial-gradient(50%_50%_at_50%_50%,rgba(110,84,255,0)_0%,rgba(255,255,255,0.12)_100%),#6E54FF]', + 'shadow-[0_1px_2px_0_rgba(0,0,0,0.20),0_1px_0.5px_0_rgba(255,255,255,0.25)_inset,0_-1px_0.5px_0_rgba(255,255,255,0.25)_inset,0_0_0_1px_rgba(79,71,235,0.90)]', + 'hover:bg-[radial-gradient(50%_50%_at_50%_50%,rgba(110,84,255,0.66)_29.81%,rgba(255,255,255,0.50)_100%),#6E54FF]', + 'hover:shadow-[0_1px_2px_0_rgba(0,0,0,0.20),0_0.75px_0.66px_0_rgba(255,255,255,0.80)_inset,0_-0.75px_0.66px_0_rgba(255,255,255,0.80)_inset,0_0_0_1px_rgba(79,71,235,0.50)]', + ], + secondary: [ + 'rounded-md text-white', + 'bg-[radial-gradient(50%_50%_at_50%_50%,rgba(23,23,23,0.20)_0%,rgba(163,163,163,0.16)_100%),#0A0A0A]', + 'shadow-[0_1px_2px_0_rgba(0,0,0,0.20),0_0.5px_0.5px_0_rgba(255,255,255,0.25)_inset,0_-0.5px_0.5px_0_rgba(255,255,255,0.25)_inset,0_0_0_1px_rgba(0,0,0,0.80)]', + 'hover:bg-[radial-gradient(50%_50%_at_50%_50%,rgba(23,23,23,0.66)_0%,rgba(163,163,163,0.53)_100%),#0A0A0A]', + 'hover:shadow-[0_1px_2px_0_rgba(0,0,0,0.20),0_0.5px_0.5px_0_rgba(255,255,255,0.25)_inset,0_-0.5px_0.5px_0_rgba(255,255,255,0.25)_inset,0_0_0_1px_rgba(0,0,0,0.80)]', + ], + }, + size: { + default: 'h-9 px-4 py-2', + sm: 'h-8 px-3 py-1.5', + lg: 'h-10 px-6 py-2.5', + }, + }, + defaultVariants: { + variant: 'primary', + size: 'default', + }, + }, +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps {} + +const Button = forwardRef( + ({ className, variant, size, ...props }, ref) => { + return ( +