Skip to content

Commit d4fd58a

Browse files
committed
Đổi giao diện scan kiểu ledger cổ điển
1 parent d39b871 commit d4fd58a

3 files changed

Lines changed: 465 additions & 381 deletions

File tree

scan/public/favicon.svg

Lines changed: 2 additions & 2 deletions
Loading

scan/src/App.vue

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,29 @@
4242
:title="githubActionTitle"
4343
@click="canLinkGitHub && startGitHubWalletLink()"
4444
>
45-
<GitPullRequest :size="16" />
45+
<GitPullRequest :size="17" />
4646
<span>
4747
<small>GitHub</small>
4848
<strong>{{ githubAccountLabel }}</strong>
4949
</span>
5050
</button>
51+
<button
52+
v-if="githubLinked"
53+
class="icon-mini github-copy-button"
54+
type="button"
55+
title="Copy GitHub account"
56+
@click="copyValue(githubAccountLabel)"
57+
>
58+
<Copy :size="15" />
59+
</button>
5160
</div>
5261
<button
5362
:class="['api-nav-link', route.name === 'api' ? 'active' : '']"
5463
type="button"
5564
title="Open API docs"
5665
@click="openApiDocs"
5766
>
58-
<FileJson :size="17" />
67+
<Braces :size="18" />
5968
<span>API</span>
6069
</button>
6170
<button class="icon-button" type="button" title="Refresh" @click="loadExplorerData">
@@ -172,12 +181,17 @@
172181
</div>
173182

174183
<TransactionTable
175-
:entries="visibleEntries"
184+
:entries="displayedEntries"
176185
:token-symbol="tokenSymbol"
177186
@go-tx="openTx"
178187
@go-block="openBlock"
179188
@go-address="openAddress"
180189
/>
190+
<div v-if="hasMoreTransactions || showAllTransactions" class="table-more">
191+
<button type="button" @click="showAllTransactions = !showAllTransactions">
192+
{{ showAllTransactions ? 'Show fewer transactions' : 'View more transactions ->' }}
193+
</button>
194+
</div>
181195
</div>
182196

183197
<aside class="side-rail">
@@ -209,36 +223,17 @@
209223
</dl>
210224
</section>
211225

212-
<section class="rail-panel">
226+
<section class="rail-panel about-panel">
213227
<div class="panel-head compact">
214228
<div>
215-
<p>Hash Chain</p>
216-
<h2>Verification</h2>
229+
<p>About MergeOS</p>
217230
</div>
218-
<span :class="['pill', chain.ok ? 'good' : 'bad']">{{ chain.ok ? 'Valid' : 'Check' }}</span>
219231
</div>
220-
<div class="chain-proof">
221-
<ShieldCheck :size="28" />
222-
<strong>{{ chain.ok ? 'All links match' : `${chain.issues.length} issues found` }}</strong>
223-
<small>{{ shortHash(chain.latestHash, 12, 10) }}</small>
224-
</div>
225-
</section>
226-
227-
<section class="rail-panel">
228-
<div class="panel-head compact">
229-
<div>
230-
<p>Addresses</p>
231-
<h2>Top accounts</h2>
232-
</div>
233-
</div>
234-
<div class="account-list">
235-
<button v-for="account in topAccounts" :key="account.account" type="button" @click="openAddress(account.account)">
236-
<span>
237-
<strong>{{ shortHash(account.account, 16, 8) }}</strong>
238-
<small>{{ accountRole(account.account) }}</small>
239-
</span>
240-
<b>{{ account.tx_count }}</b>
241-
</button>
232+
<div class="about-copy">
233+
<span class="about-icon" aria-hidden="true">
234+
<Keyboard :size="42" />
235+
</span>
236+
<p>MergeOS is a decentralized ledger system for verifying contributions and rewarding real work onchain.</p>
242237
</div>
243238
</section>
244239
</aside>
@@ -258,22 +253,23 @@
258253
<script setup>
259254
import { computed, defineAsyncComponent, defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue';
260255
import {
261-
Activity,
262256
AlertTriangle,
263257
ArrowDownLeft,
264258
ArrowUpRight,
265-
Blocks,
266-
CheckCircle2,
259+
Braces,
260+
Coins,
267261
Copy,
268262
ExternalLink,
269-
FileJson,
263+
FileText,
270264
Fingerprint,
271265
GitPullRequest,
266+
Keyboard,
272267
LoaderCircle,
273268
RefreshCw,
274269
RotateCcw,
275270
Search,
276271
ShieldCheck,
272+
Trophy,
277273
WalletCards,
278274
} from '@lucide/vue';
279275
import {
@@ -293,7 +289,6 @@ import {
293289
shortHash,
294290
sortLedgerEntries,
295291
tokenAmountFromCents,
296-
verifyLedgerChain,
297292
} from './explorer.js';
298293
299294
const ApiDocs = defineAsyncComponent(() => import('./ApiDocs.vue'));
@@ -316,6 +311,7 @@ const lastSyncAt = ref(null);
316311
const searchInput = ref('');
317312
const queryFilter = ref('');
318313
const typeFilter = ref('all');
314+
const showAllTransactions = ref(false);
319315
const route = ref(parseRoute());
320316
321317
const tokenSymbol = computed(() => config.value?.token_symbol || marketplace.value?.stats?.token_symbol || 'MRG');
@@ -337,11 +333,11 @@ const githubActionTitle = computed(() => {
337333
const entries = computed(() => sortLedgerEntries(rawEntries.value));
338334
const newestEntries = computed(() => entries.value.slice().reverse());
339335
const accounts = computed(() => aggregateAccounts(entries.value));
340-
const chain = computed(() => verifyLedgerChain(entries.value));
341336
const stats = computed(() => buildExplorerStats(entries.value, marketplace.value, tokenSymbol.value));
342337
const ledgerTypes = computed(() => Array.from(new Set(entries.value.map((entry) => entry.type))).sort());
343338
const visibleEntries = computed(() => filterEntries(newestEntries.value, { query: queryFilter.value, type: typeFilter.value }));
344-
const topAccounts = computed(() => accounts.value.slice(0, 6));
339+
const displayedEntries = computed(() => (showAllTransactions.value ? visibleEntries.value : visibleEntries.value.slice(0, 5)));
340+
const hasMoreTransactions = computed(() => visibleEntries.value.length > displayedEntries.value.length);
345341
const lastSyncLabel = computed(() => {
346342
if (!lastSyncAt.value) return 'pending';
347343
return lastSyncAt.value.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
@@ -367,10 +363,10 @@ const selectedBlockEntry = computed(() => {
367363
return entries.value.find((entry) => entry.sequence === sequence);
368364
});
369365
const statCards = computed(() => [
370-
{ label: 'Ledger Entries', value: formatCompact(stats.value.totalTransactions), icon: Activity, tone: 'blue' },
371-
{ label: 'MRG Minted', value: `${formatCompact(stats.value.mintedTokens)} ${tokenSymbol.value}`, icon: WalletCards, tone: 'green' },
372-
{ label: 'Verified Funding', value: formatLedgerAmount(stats.value.fundingCents), icon: CheckCircle2, tone: 'teal' },
373-
{ label: 'Ledger Height', value: `#${formatCompact(stats.value.chainHeight)}`, icon: Blocks, tone: 'amber' },
366+
{ label: 'Ledger Entries', value: formatCompact(stats.value.totalTransactions), icon: FileText, tone: 'green' },
367+
{ label: 'MRG Minted', value: `${formatCompact(stats.value.mintedTokens)} ${tokenSymbol.value}`, icon: Coins, tone: 'green' },
368+
{ label: 'Verified Funding', value: formatLedgerAmount(stats.value.fundingCents), icon: ShieldCheck, tone: 'green' },
369+
{ label: 'Ledger Height', value: `#${formatCompact(stats.value.chainHeight)}`, icon: Trophy, tone: 'gold' },
374370
]);
375371
376372
onMounted(() => {
@@ -621,6 +617,7 @@ function normalizeMarketplace(payload = {}) {
621617
function submitSearch() {
622618
const query = searchInput.value.trim();
623619
queryFilter.value = query;
620+
showAllTransactions.value = false;
624621
if (!query) {
625622
goHome();
626623
return;
@@ -640,6 +637,7 @@ function resetFilters() {
640637
searchInput.value = '';
641638
queryFilter.value = '';
642639
typeFilter.value = 'all';
640+
showAllTransactions.value = false;
643641
}
644642
645643
function openTx(hash) {

0 commit comments

Comments
 (0)