b6a4bd0418
Full-featured explorer consuming the daemon REST API: - Home dashboard with chain stats, latest blocks, staking info - Block list with pagination and block detail pages - Transaction detail with inputs/outputs tables - Address lookup with balance, UTXOs, and tx history - Staking dashboard with difficulty chart (Chart.js) - Network info with peer table - Mempool viewer - API documentation page for all 30+ REST endpoints - Search by block hash, height, txid, or address - Dark theme with Tailwind CSS v4 - SSR via adapter-node for SEO Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.2 KiB
Svelte
79 lines
2.2 KiB
Svelte
<script lang="ts">
|
|
import StatsCard from '$lib/components/StatsCard.svelte';
|
|
import BlockTable from '$lib/components/BlockTable.svelte';
|
|
import { formatNumber, formatAmount, formatDifficulty, truncateHash } from '$lib/utils';
|
|
|
|
let { data } = $props();
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>Triangles Block Explorer - Dashboard</title>
|
|
</svelte:head>
|
|
|
|
{#if data.error}
|
|
<div class="bg-tri-red/10 border border-tri-red/30 rounded-lg p-4 mb-6 text-tri-red text-sm">
|
|
Unable to connect to daemon: {data.error}
|
|
</div>
|
|
{/if}
|
|
|
|
{#if data.chain}
|
|
<!-- Stats Grid -->
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
|
<StatsCard label="Block Height" value={formatNumber(data.chain.blocks)} />
|
|
<StatsCard
|
|
label="Supply"
|
|
value="{formatAmount(data.chain.moneysupply)} TRI"
|
|
sub="of 120,000 max"
|
|
/>
|
|
<StatsCard
|
|
label="PoS Difficulty"
|
|
value={formatDifficulty(data.chain.difficulty['proof-of-stake'])}
|
|
/>
|
|
<StatsCard
|
|
label="Best Block"
|
|
value={truncateHash(data.chain.bestblockhash, 8)}
|
|
/>
|
|
</div>
|
|
|
|
<!-- Staking + Mining stats -->
|
|
{#if data.staking || data.mining}
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
|
{#if data.staking}
|
|
<StatsCard
|
|
label="Staking"
|
|
value={data.staking.staking ? 'Active' : 'Inactive'}
|
|
sub="Network weight: {formatNumber(data.staking.netstakeweight)}"
|
|
/>
|
|
{/if}
|
|
{#if data.mining}
|
|
<StatsCard
|
|
label="Stake Interest"
|
|
value="{data.mining.stakeinterest}%"
|
|
sub="Annual rate"
|
|
/>
|
|
<StatsCard
|
|
label="Network Hash"
|
|
value="{data.mining.netmhashps.toFixed(2)} MH/s"
|
|
/>
|
|
<StatsCard
|
|
label="Pooled Txs"
|
|
value={formatNumber(data.mining.pooledtx)}
|
|
/>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
{/if}
|
|
|
|
<!-- Latest Blocks -->
|
|
<div class="bg-tri-surface border border-tri-border rounded-lg overflow-hidden">
|
|
<div class="flex items-center justify-between px-4 py-3 border-b border-tri-border">
|
|
<h2 class="text-white font-semibold">Latest Blocks</h2>
|
|
<a href="/blocks" class="text-tri-accent text-sm hover:text-tri-accent-light">View all →</a>
|
|
</div>
|
|
{#if data.blocks.length > 0}
|
|
<BlockTable blocks={data.blocks} />
|
|
{:else}
|
|
<div class="p-8 text-center text-tri-muted">No blocks available</div>
|
|
{/if}
|
|
</div>
|