Skip to content

Commit 4468c1b

Browse files
Nethereum.Explorer: Blazor Server blockchain explorer component library
Razor Class Library providing embeddable explorer UI for Ethereum-compatible chains with indexed storage, ABI decoding, EVM debugging, MUD world browsing, token views, and EIP-6963 wallet integration.
1 parent 20a1140 commit 4468c1b

File tree

98 files changed

+13620
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+13620
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
@using Microsoft.Extensions.Options
2+
@inject ExplorerLocalizer L
3+
@inject IOptions<ExplorerOptions> Options
4+
5+
<!DOCTYPE html>
6+
<html lang="en">
7+
8+
<head>
9+
<meta charset="utf-8" />
10+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
11+
<title>@Options.Value.ExplorerTitle</title>
12+
<base href="/" />
13+
<link rel="icon" type="image/png" href="@(Options.Value.FaviconUrl ?? "_content/Nethereum.Explorer/favicon.png")" />
14+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
15+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
16+
<link rel="stylesheet" href="@($"{System.Reflection.Assembly.GetEntryAssembly()?.GetName().Name ?? "Nethereum.Explorer"}.styles.css")" />
17+
<link rel="stylesheet" href="_content/Nethereum.Explorer/app.css" />
18+
<link rel="stylesheet" href="_content/Nethereum.Blazor.Solidity/solidity-debugger.css" />
19+
<HeadOutlet />
20+
</head>
21+
22+
<body>
23+
<header class="navbar navbar-expand-lg navbar-dark bg-dark-blue fixed-top">
24+
<div class="container-fluid">
25+
<a class="navbar-brand d-flex align-items-center" href="/">
26+
<img src="@(Options.Value.LogoUrl ?? "_content/Nethereum.Explorer/nethereum-logo.png")" alt="@Options.Value.ExplorerBrandName" width="28" height="28" class="me-2" />
27+
<span class="explorer-brand-name">@Options.Value.ExplorerBrandName</span><span class="explorer-brand-suffix ms-1">@Options.Value.ExplorerBrandSuffix</span>
28+
</a>
29+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
30+
<span class="navbar-toggler-icon"></span>
31+
</button>
32+
<div class="collapse navbar-collapse" id="navbarNav">
33+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
34+
<li class="nav-item">
35+
<a class="nav-link" href="/">@L[ExplorerKeys.Nav.Dashboard]</a>
36+
</li>
37+
<li class="nav-item">
38+
<a class="nav-link" href="/blocks">@L[ExplorerKeys.Nav.Blocks]</a>
39+
</li>
40+
<li class="nav-item">
41+
<a class="nav-link" href="/transactions">@L[ExplorerKeys.Nav.Txns]</a>
42+
</li>
43+
<li class="nav-item">
44+
<a class="nav-link" href="/contracts">@L[ExplorerKeys.Nav.Contracts]</a>
45+
</li>
46+
<li class="nav-item">
47+
<a class="nav-link" href="/accounts">@L[ExplorerKeys.Nav.AccountsNav]</a>
48+
</li>
49+
@if (Options.Value.EnablePendingTransactions)
50+
{
51+
<li class="nav-item">
52+
<a class="nav-link" href="/pending"><i class="bi bi-hourglass-split me-1"></i>Pending</a>
53+
</li>
54+
}
55+
<MudNavItem @rendermode="InteractiveServer" />
56+
</ul>
57+
<SearchBar @rendermode="InteractiveServer" />
58+
<button class="theme-toggle ms-3" onclick="toggleTheme()" title="Toggle theme">
59+
<i class="bi bi-sun-fill" id="themeIcon"></i>
60+
</button>
61+
<div class="ms-2">
62+
<LanguageSelector @rendermode="InteractiveServer" />
63+
</div>
64+
<div class="ms-2">
65+
<EIP6963Wallet @rendermode="InteractiveServer" Theme="EIP6963Wallet.ThemeType.None" />
66+
</div>
67+
</div>
68+
</div>
69+
</header>
70+
71+
<main class="container-fluid explorer-main">
72+
<Routes @rendermode="InteractiveServer" />
73+
</main>
74+
75+
<ToastContainer @rendermode="InteractiveServer" />
76+
77+
<footer class="container-fluid text-center py-4 explorer-footer">
78+
<div class="d-flex justify-content-center align-items-center gap-3 flex-wrap explorer-footer-inner">
79+
<span class="text-color-secondary">@L[ExplorerKeys.Nav.ExplorerTitle]</span>
80+
<span class="explorer-footer-sep">|</span>
81+
<a href="https://nethereum.com" target="_blank" rel="noopener" class="explorer-footer-link">nethereum.com</a>
82+
<span class="explorer-footer-sep">|</span>
83+
<a href="https://github.com/Nethereum/Nethereum" target="_blank" rel="noopener" class="explorer-footer-link"><i class="bi bi-github me-1"></i>GitHub</a>
84+
<span class="explorer-footer-sep">|</span>
85+
<span class="explorer-footer-powered">@L[ExplorerKeys.Nav.PoweredBy]</span>
86+
</div>
87+
</footer>
88+
89+
<script src="_content/Nethereum.Explorer/explorer-interop.js"></script>
90+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
91+
<script src="_content/Nethereum.Blazor/NethereumEIP6963.js"></script>
92+
<script src="_framework/blazor.web.js"></script>
93+
</body>
94+
95+
</html>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
@using Nethereum.Explorer.Components.Shared
2+
@using Nethereum.Explorer.Services
3+
@inject ExplorerLocalizer L
4+
5+
<div class="card">
6+
<div class="card-header d-flex justify-content-between align-items-center">
7+
<span><i class="bi bi-boxes me-2"></i>@L[ExplorerKeys.Home.LatestBlocks]</span>
8+
<a href="/blocks" class="btn btn-outline-primary btn-sm">@L[ExplorerKeys.Shared.ViewAll]</a>
9+
</div>
10+
<div class="card-body p-0">
11+
@if (Blocks == null || !Blocks.Any())
12+
{
13+
<EmptyState IconClass="bi bi-boxes" Title="@L[ExplorerKeys.Home.NoBlocksYet]" Subtitle="@L[ExplorerKeys.Home.WaitingForBlocks]" />
14+
}
15+
else
16+
{
17+
<div class="table-responsive">
18+
<table class="table table-hover mb-0">
19+
<thead>
20+
<tr>
21+
<th>@L[ExplorerKeys.Table.Block]</th>
22+
<th>@L[ExplorerKeys.Table.Age]</th>
23+
<th>@L[ExplorerKeys.Table.Txns]</th>
24+
<th>@L[ExplorerKeys.Table.GasUsed]</th>
25+
<th>@L[ExplorerKeys.Table.Validator]</th>
26+
</tr>
27+
</thead>
28+
<tbody>
29+
@foreach (var block in Blocks)
30+
{
31+
var gasPercent = ExplorerFormatUtils.GasPercentage(block.GasUsed, block.GasLimit);
32+
<tr>
33+
<td>
34+
<a href="/block/@block.BlockNumber">
35+
<i class="bi bi-box me-1"></i>@block.BlockNumber
36+
</a>
37+
</td>
38+
<td class="text-nowrap" title="@ExplorerFormatUtils.FormatTimestamp(block.TimeStamp)">
39+
<span class="text-color-primary text-xs">@ExplorerFormatUtils.FormatAge(block.TimeStamp)</span>
40+
</td>
41+
<td>
42+
<span class="badge badge-info">@block.TransactionCount</span>
43+
</td>
44+
<td>
45+
<div class="d-flex align-items-center gap-2">
46+
<span class="text-color-warning text-base">@ExplorerFormatUtils.FormatGas(block.GasUsed)</span>
47+
<div class="gas-bar explorer-gas-bar-sm">
48+
<div class="gas-bar-fill" style="width: @gasPercent%"></div>
49+
</div>
50+
</div>
51+
</td>
52+
<td>
53+
<HexDisplay Value="@block.Miner" Link="@($"/account/{block.Miner}")" MaxLength="14" ShowCopy="false" />
54+
</td>
55+
</tr>
56+
}
57+
</tbody>
58+
</table>
59+
</div>
60+
}
61+
</div>
62+
</div>
63+
64+
@code {
65+
[Parameter] public List<IBlockView>? Blocks { get; set; }
66+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
@using Nethereum.Explorer.Components.Shared
2+
@using Nethereum.Explorer.Services
3+
@inject ExplorerChainService ChainService
4+
@inject ExplorerLocalizer L
5+
6+
<div class="card">
7+
<div class="card-header d-flex justify-content-between align-items-center">
8+
<span><i class="bi bi-arrow-left-right me-2"></i>@L[ExplorerKeys.Home.LatestTransactions]</span>
9+
<a href="/transactions" class="btn btn-outline-primary btn-sm">@L[ExplorerKeys.Shared.ViewAll]</a>
10+
</div>
11+
<div class="card-body p-0">
12+
@if (Transactions == null || !Transactions.Any())
13+
{
14+
<EmptyState IconClass="bi bi-arrow-left-right" Title="@L[ExplorerKeys.Home.NoTransactionsYet]" Subtitle="@L[ExplorerKeys.Home.WaitingForTransactions]" />
15+
}
16+
else
17+
{
18+
<div class="table-responsive">
19+
<table class="table table-hover mb-0">
20+
<thead>
21+
<tr>
22+
<th></th>
23+
<th>@L[ExplorerKeys.Table.TxHash]</th>
24+
<th>@L[ExplorerKeys.Table.Method]</th>
25+
<th>@L[ExplorerKeys.Table.Block]</th>
26+
<th>@L[ExplorerKeys.Table.From]</th>
27+
<th>@L[ExplorerKeys.Table.To]</th>
28+
<th>@L[ExplorerKeys.Table.Value] (@ChainService.CurrencySymbol)</th>
29+
</tr>
30+
</thead>
31+
<tbody>
32+
@foreach (var tx in Transactions)
33+
{
34+
<tr>
35+
<td class="text-center px-1 explorer-status-icon-cell">
36+
@if (tx.Failed)
37+
{
38+
<i class="bi bi-x-circle-fill text-color-danger" title="@L[ExplorerKeys.TransactionDetail.Failed]"></i>
39+
}
40+
else
41+
{
42+
<i class="bi bi-check-circle-fill text-color-success" title="@L[ExplorerKeys.TransactionDetail.Success]"></i>
43+
}
44+
</td>
45+
<td>
46+
<HexDisplay Value="@tx.Hash" Link="@($"/transaction/{tx.Hash}")" MaxLength="18" ShowCopy="false" />
47+
</td>
48+
<td>
49+
<span class="badge @ExplorerFormatUtils.GetMethodBadgeCssClass(tx.Input)">@ExplorerFormatUtils.GetMethodName(tx.Input)</span>
50+
</td>
51+
<td>
52+
<a href="/block/@tx.BlockNumber">@tx.BlockNumber</a>
53+
</td>
54+
<td>
55+
<HexDisplay Value="@tx.AddressFrom" Link="@($"/account/{tx.AddressFrom}")" MaxLength="14" ShowCopy="false" />
56+
</td>
57+
<td>
58+
@if (ExplorerFormatUtils.IsContractCreation(tx.AddressTo))
59+
{
60+
<span class="badge badge-info">Create</span>
61+
}
62+
else
63+
{
64+
<HexDisplay Value="@tx.AddressTo" Link="@($"/account/{tx.AddressTo}")" MaxLength="14" ShowCopy="false" />
65+
}
66+
</td>
67+
<td class="text-color-primary">@ExplorerFormatUtils.FormatEth(tx.Value) @ChainService.CurrencySymbol</td>
68+
</tr>
69+
}
70+
</tbody>
71+
</table>
72+
</div>
73+
}
74+
</div>
75+
</div>
76+
77+
@code {
78+
[Parameter] public List<ITransactionView>? Transactions { get; set; }
79+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@inherits LayoutComponentBase
2+
@inject ExplorerLocalizer L
3+
4+
<article class="content">
5+
@Body
6+
</article>
7+
8+
<div id="blazor-error-ui" data-nosnippet>
9+
@L[ExplorerKeys.Errors.UnhandledError]
10+
<a href="." class="reload">@L[ExplorerKeys.Errors.Reload]</a>
11+
<span class="dismiss">&#x1F5D9;</span>
12+
</div>

0 commit comments

Comments
 (0)