diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 692f7d863..58d555657 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -2,7 +2,7 @@
-
+
 
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 8a0a06f0c..1dc280514 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input } from '@angular/core'; -import { Subscription, Observable, fromEvent, merge, of, combineLatest, timer } from 'rxjs'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subscription, Observable, fromEvent, merge, of, combineLatest } from 'rxjs'; import { MempoolBlock } from '../../interfaces/websocket.interface'; import { StateService } from '../../services/state.service'; import { Router } from '@angular/router'; @@ -9,11 +9,18 @@ import { specialBlocks } from '../../app.constants'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; import { Location } from '@angular/common'; import { DifficultyAdjustment } from '../../interfaces/node-api.interface'; +import { animate, style, transition, trigger } from '@angular/animations'; @Component({ selector: 'app-mempool-blocks', templateUrl: './mempool-blocks.component.html', styleUrls: ['./mempool-blocks.component.scss'], + animations: [trigger('blockEntryTrigger', [ + transition(':enter', [ + style({ transform: 'translateX(-155px)' }), + animate('2s 0s ease', style({ transform: '' })), + ]), + ])], changeDetection: ChangeDetectionStrategy.OnPush, }) export class MempoolBlocksComponent implements OnInit, OnDestroy { @@ -32,12 +39,14 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { isLoadingWebsocketSubscription: Subscription; blockSubscription: Subscription; networkSubscription: Subscription; + chainTipSubscription: Subscription; network = ''; now = new Date().getTime(); timeOffset = 0; showMiningInfo = false; timeLtrSubscription: Subscription; timeLtr: boolean; + animateEntry: boolean = false; blockWidth = 125; blockPadding = 30; @@ -53,6 +62,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { resetTransitionTimeout: number; + chainTip: number = -1; blockIndex = 1; constructor( @@ -69,6 +79,8 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { } ngOnInit() { + this.chainTip = this.stateService.latestBlockHeight; + if (['', 'testnet', 'signet'].includes(this.stateService.network)) { this.enabledMiningInfoIfNeeded(this.location.path()); this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); @@ -155,11 +167,24 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.blockSubscription = this.stateService.blocks$ .subscribe(([block]) => { + if (this.chainTip === -1) { + this.animateEntry = block.height === this.stateService.latestBlockHeight; + } else { + this.animateEntry = block.height > this.chainTip; + } + + this.chainTip = this.stateService.latestBlockHeight; if (block?.extras?.matchRate >= 66 && !this.tabHidden) { this.blockIndex++; } }); + this.chainTipSubscription = this.stateService.chainTip$.subscribe((height) => { + if (this.chainTip === -1) { + this.chainTip = height; + } + }); + this.networkSubscription = this.stateService.networkChanged$ .subscribe((network) => this.network = network); @@ -195,11 +220,12 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.blockSubscription.unsubscribe(); this.networkSubscription.unsubscribe(); this.timeLtrSubscription.unsubscribe(); + this.chainTipSubscription.unsubscribe(); clearTimeout(this.resetTransitionTimeout); } trackByFn(index: number, block: MempoolBlock) { - return block.index; + return (block.isStack) ? 'stack' : block.height; } reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { @@ -216,6 +242,9 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { lastBlock.medianFee = this.median(lastBlock.feeRange); lastBlock.totalFees += block.totalFees; } + if (blocks.length) { + blocks[blocks.length - 1].isStack = blocks[blocks.length - 1].blockVSize > this.stateService.blockVSize; + } return blocks; } @@ -334,4 +363,4 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { } return emptyBlocks; } -} +} \ No newline at end of file diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 96f7530c9..46416857e 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -43,6 +43,7 @@ export interface MempoolBlock { totalFees: number; feeRange: number[]; index: number; + isStack?: boolean; } export interface MempoolBlockWithTransactions extends MempoolBlock {