simplify colors of block explorer homepage

This commit is contained in:
Victor Oliva
2024-11-08 19:00:40 +07:00
parent 293d7b6085
commit c1b7a9252a
10 changed files with 262 additions and 230 deletions
+10 -10
View File
@@ -10,17 +10,17 @@ import { Transactions } from "./pages/Transactions"
export default function App() {
return (
<div className="w-full max-w-screen-lg h-screen bg-polkadot-950 flex flex-col">
<div className="w-full max-w-screen-lg h-screen bg-background flex flex-col">
<Header />
<Routes>
<Route path="explorer/*" element={<Explorer />} />
<Route path="extrinsics/*" element={<Extrinsics />} />
<Route path="storage/*" element={<Storage />} />
<Route path="constants/*" element={<Constants />} />
<Route path="runtimeCalls/*" element={<RuntimeCalls />} />
<Route path="metadata/*" element={<Metadata />} />
<Route path="*" element={<Navigate to="/extrinsics" replace />} />
</Routes>
<Routes>
<Route path="explorer/*" element={<Explorer />} />
<Route path="extrinsics/*" element={<Extrinsics />} />
<Route path="storage/*" element={<Storage />} />
<Route path="constants/*" element={<Constants />} />
<Route path="runtimeCalls/*" element={<RuntimeCalls />} />
<Route path="metadata/*" element={<Metadata />} />
<Route path="*" element={<Navigate to="/extrinsics" replace />} />
</Routes>
<Transactions />
</div>
)
+4 -4
View File
@@ -19,7 +19,7 @@ export const CircularProgress: FC<{
`}
strokeWidth={STROKE_W}
fill="transparent"
className="transition-all ease-linear stroke-polkadot-500"
className="transition-all ease-linear stroke-primary"
opacity="0.3"
/>
{progress ? (
@@ -33,7 +33,7 @@ export const CircularProgress: FC<{
strokeWidth={STROKE_W}
strokeLinecap="round"
fill="transparent"
className="transition-all ease-linear stroke-polkadot-500"
className="transition-all ease-linear stroke-primary"
opacity="0.7"
/>
) : null}
@@ -48,7 +48,7 @@ export const CircularProgress: FC<{
strokeWidth={STROKE_W}
strokeLinecap="round"
fill="transparent"
className="transition-all ease-linear stroke-polkadot-500"
className="transition-all ease-linear stroke-primary"
/>
) : null}
<text
@@ -56,7 +56,7 @@ export const CircularProgress: FC<{
y={CENTER}
textAnchor="middle"
dy=".3em"
className="tabular-nums fill-polkadot-200"
className="tabular-nums fill-foreground/80"
>
{text}
</text>
+2 -2
View File
@@ -7,9 +7,9 @@ export const Popover: FC<
<Root open={open}>
<Trigger asChild>{children}</Trigger>
<Portal>
<Content className="bg-polkadot-950 border border-polkadot-700 p-2 rounded max-w-[100vw]">
<Content className="bg-popover text-popover-foreground border p-2 rounded max-w-[100vw]">
{content}
<Arrow className="fill-polkadot-700" />
<Arrow className="fill-border" />
</Content>
</Portal>
</Root>
+34 -31
View File
@@ -39,54 +39,56 @@ dialog {
opacity: 1;
pointer-events: all;
}
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--popover-foreground: 240 10% 3.9%;
--primary: 328 100% 45%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 328 100% 45%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
--card: 24 9.8% 10%;
--card-foreground: 0 0% 95%;
--popover: 0 0% 9%;
--popover-foreground: 0 0% 95%;
--primary: 328 100% 45%;
--primary-foreground: 355.7 100% 97.3%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--muted: 0 0% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--destructive-foreground: 0 85.7% 97.3%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 328 100% 45%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
@@ -94,6 +96,7 @@ dialog {
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
+20 -14
View File
@@ -8,6 +8,7 @@ import { map } from "rxjs"
import { blockInfoState$ } from "./block.state"
import { BlockStatusIcon, statusText } from "./Detail/BlockState"
import { filterEvt } from "./Events"
import { CopyText } from "@/components/Copy"
const maxBlockWeight$ = state(
runtimeCtx$.pipe(
@@ -51,21 +52,23 @@ export const BlockPopover: FC<{ hash: string }> = ({ hash }) => {
return (
<div>
<h3 className="font-bold text-lg hover:text-polkadot-200">
<Link to={hash}>
Block{" "}
<span className="font-mono text-sm font-normal text-slate-300 hover:text-polkadot-200">
{hash}
</span>
</Link>
</h3>
<p>
Status:{" "}
<span className="inline-flex gap-1 items-center align-middle">
<div className="flex justify-between items-center gap-4 mb-2">
<h3 className="font-bold flex gap-1 items-center">
Block
<Link
to={hash}
className="font-mono font-normal text-primary/70 hover:text-primary"
>
{hash.slice(0, 18)}…
</Link>
<CopyText className="ml-1" text={hash} binary />
</h3>
<p className="flex gap-1">
Status:
<BlockStatusIcon state={block.status} />
{statusText[block.status]}
</span>
</p>
</p>
</div>
<div className="flex justify-between items-start">
{eventGroups && (
<div>
@@ -83,7 +86,10 @@ export const BlockPopover: FC<{ hash: string }> = ({ hash }) => {
<td className="px-2">
{filteredEvents}/
{eventGroups["ApplyExtrinsic"]?.length ?? 0}
<span className="text-slate-300"> (filtered/total)</span>
<span className="text-popover-foreground/60">
{" "}
(filtered/total)
</span>
</td>
</tr>
<tr>
+58 -63
View File
@@ -7,6 +7,7 @@ import { combineLatest, debounceTime, map, switchMap } from "rxjs"
import { twMerge } from "tailwind-merge"
import { BlockInfo, blocksByHeight$, finalized$ } from "./block.state"
import { BlockPopover } from "./BlockPopover"
import * as Finalizing from "./FinalizingTable"
const best$ = chainHead$.pipeState(switchMap((chainHead) => chainHead.best$))
@@ -101,69 +102,63 @@ export const BlockTable = () => {
if (!finalized) return null
return (
<div className="w-full px-3 py-2 border border-polkadot-700">
<h2 className="font-bold p-2 border-b border-slate-400 mb-2">
Recent Blocks
</h2>
<table className="border-collapse m-auto">
<tbody>
{rows.map((row, i) => (
<tr
key={row.block.hash}
className={twMerge(
row.block.number <= finalized.number ? "bg-polkadot-900" : "",
row.block.number === finalized.number &&
row.position === 0 &&
"border-t",
)}
>
{rows[i - 1]?.block.number !== row.block.number ? (
<td
rowSpan={numberSpan(i)}
className={twMerge(
"px-2",
numberSpan(i) > 1
? twMerge(
i > 0 ? "border-y" : "border-b",
"border-slate-500",
)
: null,
row.block.number === finalized.number && "border-t-white",
row.block.number === finalized.number + 1 &&
"border-b-white",
)}
>
{row.block.number.toLocaleString()}
</td>
) : null}
<td className="p-0">
<ForkRenderer row={row} />
<Finalizing.Root>
<Finalizing.Title>Recent Blocks</Finalizing.Title>
<Finalizing.Table>
{rows.map((row, i) => (
<Finalizing.Row
key={row.block.hash}
number={row.block.number}
finalized={finalized.number}
firstInGroup={row.position === 0}
>
{rows[i - 1]?.block.number !== row.block.number ? (
<td
rowSpan={numberSpan(i)}
className={twMerge(
"px-2",
numberSpan(i) > 1
? twMerge(
i > 0 ? "border-y" : "border-b",
"border-card-foreground/25",
)
: null,
row.block.number === finalized.number &&
"border-t-card-foreground/50",
row.block.number === finalized.number + 1 &&
"border-b-card-foreground/50",
)}
>
{row.block.number.toLocaleString()}
</td>
<td className="max-w-xs w-full">
<div className="flex gap-1">
<Popover content={<BlockPopover hash={row.block.hash} />}>
<button
className={twMerge(
"overflow-hidden text-ellipsis whitespace-nowrap font-mono text-sm",
"hover:text-polkadot-200",
row.position === 0
? ""
: row.block.number > finalized.number
? "opacity-80"
: "opacity-50",
)}
>
{row.block.hash}
</button>
</Popover>
<CopyText text={row.block.hash} binary />
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
) : null}
<td className="p-0">
<ForkRenderer row={row} />
</td>
<td className="max-w-xs w-full">
<div className="flex gap-1">
<Popover content={<BlockPopover hash={row.block.hash} />}>
<button
className={twMerge(
"overflow-hidden text-ellipsis whitespace-nowrap font-mono text-sm",
"text-card-foreground/80 hover:text-card-foreground/100",
row.position === 0
? ""
: row.block.number > finalized.number
? "opacity-80"
: "opacity-50",
)}
>
{row.block.hash}
</button>
</Popover>
<CopyText text={row.block.hash} binary />
</div>
</td>
</Finalizing.Row>
))}
</Finalizing.Table>
</Finalizing.Root>
)
}
@@ -179,7 +174,7 @@ const ForkRenderer: FC<{ row: PositionedBlock }> = ({ row }) => {
<svg
height={CELL_HEIGHT}
width={CELL_WIDTH * totalCells}
className="stroke-polkadot-200"
className="stroke-card-foreground/60"
>
{row.branches.map((branch, i) => (
<line
+56 -54
View File
@@ -16,6 +16,8 @@ import { JsonDisplay } from "@/components/JsonDisplay"
import { groupBy } from "@/lib/groupBy"
import { Link } from "react-router-dom"
import { BlockStatusIcon, statusText } from "./Detail/BlockState"
import * as Finalizing from "./FinalizingTable"
import { CopyText } from "@/components/Copy"
export const Events = () => {
const events = useStateObservable(recentEvents$)
@@ -35,71 +37,70 @@ export const Events = () => {
}
return (
<div className="w-full px-3 py-2 border border-polkadot-700">
<h2 className="font-bold p-2 border-b border-slate-400 mb-2">
Recent Events
</h2>
<table className="w-full">
<tbody>
{events.map((evt, idx) => {
const key = eventKey(evt)
const span = numberSpan(idx)
<Finalizing.Root>
<Finalizing.Title>Recent Events</Finalizing.Title>
<Finalizing.Table>
{events.map((evt, idx) => {
const key = eventKey(evt)
const span = numberSpan(idx)
return (
<tr
key={`${evt.hash}-${evt.extrinsicNumber}-${evt.index}`}
className={twMerge(
idx === finalizedIdx ? "border-t border-white" : "",
finalized && evt.number <= finalized.number
? "bg-polkadot-900"
: "",
)}
>
{eventKey(events[idx - 1]) !== key && (
<td
className={twMerge(
"p-2 whitespace-nowrap",
span > 1 &&
twMerge(
idx > 0 ? "border-y" : "border-b",
"border-slate-500",
),
idx === finalizedIdx && "border-t-white",
idx === finalizedIdx - span && "border-b-white",
)}
rowSpan={span}
>
{key}
</td>
)}
<td className="p-1 w-full">
{"event" in evt ? (
<Popover content={<EventPopover event={evt} />}>
<button className="w-full p-1 text-left hover:text-polkadot-200">{`${evt.event.type}.${evt.event.value.type}`}</button>
</Popover>
) : (
`… ${evt.length} more`
return (
<Finalizing.Row
key={`${evt.hash}-${evt.extrinsicNumber}-${evt.index}`}
number={events.length - idx}
finalized={events.length - finalizedIdx}
firstInGroup
>
{eventKey(events[idx - 1]) !== key && (
<td
className={twMerge(
"p-2 whitespace-nowrap",
span > 1 &&
twMerge(
idx > 0 ? "border-y" : "border-b",
"border-card-foreground/25",
),
idx === finalizedIdx &&
"border-t-border-card-foreground/50",
idx === finalizedIdx - span &&
"border-b-border-card-foreground/50",
)}
rowSpan={span}
>
{key}
</td>
</tr>
)
})}
</tbody>
</table>
)}
<td className="p-1 w-full">
{"event" in evt ? (
<Popover content={<EventPopover event={evt} />}>
<button className="w-full p-1 text-left hover:text-polkadot-200">{`${evt.event.type}.${evt.event.value.type}`}</button>
</Popover>
) : (
`… ${evt.length} more`
)}
</td>
</Finalizing.Row>
)
})}
</Finalizing.Table>
{events.length === 0 ? (
<div className="text-slate-400">(No events yet)</div>
) : null}
</div>
</Finalizing.Root>
)
}
const EventPopover: FC<{ event: EventInfo }> = ({ event }) => {
return (
<div>
<div className="flex justify-between">
<div className="flex justify-between items-center gap-4 mb-2">
<h3 className="font-bold text-lg">
<Link to={`${event.hash}#event=${event.index}`}>
Event {eventKey(event)}
Event{" "}
<Link
to={`${event.hash}#event=${event.index}`}
className="text-primary/70 hover:text-primary"
>
{eventKey(event)}
</Link>
</h3>
<p className="flex gap-1">
@@ -108,8 +109,9 @@ const EventPopover: FC<{ event: EventInfo }> = ({ event }) => {
{statusText[event.status]}
</p>
</div>
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-slate-400">
Block: {event.hash}
<p className="overflow-hidden text-ellipsis whitespace-nowrap flex items-center gap-2">
Block: {event.hash.slice(0, 18)}…
<CopyText text={event.hash} binary />
</p>
<p className="font-bold">{`${event.event.type}.${event.event.value.type}`}</p>
<JsonDisplay src={event.event.value.value} />
+39
View File
@@ -0,0 +1,39 @@
import { FC, PropsWithChildren } from "react"
import { twMerge } from "tailwind-merge"
export const Title: FC<PropsWithChildren> = ({ children }) => (
<h2 className="font-bold p-2 border-b border-slate-400 mb-2">{children}</h2>
)
export const Table: FC<PropsWithChildren> = ({ children }) => (
<table className="border-collapse m-auto">
<tbody>{children}</tbody>
</table>
)
export const Row: FC<
PropsWithChildren<{
number: number
finalized: number
firstInGroup: boolean
}>
> = ({ children, number, finalized, firstInGroup }) => (
<tr
className={twMerge(
number <= finalized ? "bg-primary/5" : "",
number === finalized &&
firstInGroup &&
"border-t border-card-foreground/50",
)}
>
{children}
</tr>
)
export const Root: FC<PropsWithChildren> = ({ children }) => {
return (
<div className="w-full px-3 py-2 border bg-card text-card-foreground">
{children}
</div>
)
}
+12 -14
View File
@@ -16,21 +16,12 @@ const best$ = chainHead$.pipeState(
export const Summary: FC = () => {
return (
<div className="flex gap-4 items-center py-2">
<SummaryItem
title="Block Time"
className="bg-opacity-0"
>
<SummaryItem title="Block Time" className="bg-card/0 border-none">
<BlockTime />
</SummaryItem>
<div className="flex-1" />
<SummaryItem
title="Finalized"
>
{finalized$}
</SummaryItem>
<SummaryItem title="Best">
{best$}
</SummaryItem>
<SummaryItem title="Finalized">{finalized$}</SummaryItem>
<SummaryItem title="Best">{best$}</SummaryItem>
</div>
)
}
@@ -39,9 +30,16 @@ const SummaryItem: FC<
PropsWithChildren<{ title: string; className?: string }>
> = ({ title, className, children }) => {
return (
<div className={twMerge("flex flex-col items-center bg-polkadot-800 px-3 py-2", className)}>
<div
className={twMerge(
"flex flex-col items-center border rounded bg-card text-card-foreground px-3 py-2",
className,
)}
>
<h3>{title}</h3>
<div className="tabular-nums text-slate-300 text-sm">{children}</div>
<div className="tabular-nums text-sm text-card-foreground/80">
{children}
</div>
</div>
)
}
+27 -38
View File
@@ -1,5 +1,7 @@
import { Link } from "react-router-dom"
import { Link, useLocation } from "react-router-dom"
import { NetworkSwitcher } from "./Network/Network"
import { FC, PropsWithChildren } from "react"
import { twMerge } from "tailwind-merge"
export const Header = () => (
<div className="flex p-4 pb-2 items-center flex-shrink-0 gap-2">
@@ -14,43 +16,30 @@ export const Header = () => (
</h1>
</div>
<NetworkSwitcher />
<div className="flex flex-row items-center justify-end bg-polkadot-800 px-1 py-1 rounded-full text-nowrap">
<Link
to="/explorer"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Explorer
</Link>
<Link
to="/storage"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Storage
</Link>
<Link
to="/extrinsics"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Extrinsics
</Link>
<Link
to="/constants"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Constants
</Link>
<Link
to="/runtimeCalls"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Runtime Calls
</Link>
<Link
to="/metadata"
className="cursor-pointer hover:text-polkadot-0 px-3 py-1 hover:bg-polkadot-500 rounded-full"
>
Metadata
</Link>
<div className="flex flex-row items-center justify-end px-1 py-1 text-nowrap">
<NavLink to="/explorer">Explorer</NavLink>
<NavLink to="/storage">Storage</NavLink>
<NavLink to="/extrinsics">Extrinsics</NavLink>
<NavLink to="/constants">Constants</NavLink>
<NavLink to="/runtimeCalls">Runtime Calls</NavLink>
<NavLink to="/metadata">Metadata</NavLink>
</div>
</div>
)
const NavLink: FC<PropsWithChildren<{ to: string }>> = ({ to, children }) => {
const location = useLocation()
const active = location.pathname.startsWith(to)
return (
<Link
to={to}
className={twMerge(
"transition-colors text-foreground/75 hover:text-foreground cursor-pointer px-3 py-1",
active && "text-foreground font-bold",
)}
>
{children}
</Link>
)
}