Add block display mode toggle button
This commit is contained in:
		
							parent
							
								
									bd5a23ff0d
								
							
						
					
					
						commit
						a4d8f2db58
					
				| @ -12,6 +12,7 @@ | |||||||
|         class="text-center bitcoin-block mined-block blockchain-blocks-offset-{{ offset }}-index-{{ i }}" |         class="text-center bitcoin-block mined-block blockchain-blocks-offset-{{ offset }}-index-{{ i }}" | ||||||
|         [class.offscreen]="!static && count && i >= count" |         [class.offscreen]="!static && count && i >= count" | ||||||
|         id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" |         id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" | ||||||
|  |         [style]="blockTransformation" | ||||||
|         [class.blink-bg]="isSpecial(block.height)"> |         [class.blink-bg]="isSpecial(block.height)"> | ||||||
|         <a draggable="false" [routerLink]="[getHref(i, block) | relativeUrl]" [state]="{ data: { block: block } }" |         <a draggable="false" [routerLink]="[getHref(i, block) | relativeUrl]" [state]="{ data: { block: block } }" | ||||||
|           class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a> |           class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a> | ||||||
| @ -40,7 +41,7 @@ | |||||||
|                 <app-fee-rate unitClass=""></app-fee-rate> |                 <app-fee-rate unitClass=""></app-fee-rate> | ||||||
|               </div> |               </div> | ||||||
|             </ng-template> |             </ng-template> | ||||||
|             <div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-total-fees'" *ngIf="showMiningInfo$ | async; else noMiningInfo" |             <div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-total-fees'" *ngIf="blockDisplayMode === 'fees'; else noMiningInfo" | ||||||
|               class="block-size"> |               class="block-size"> | ||||||
|               <app-amount [satoshis]="block.extras?.totalFees ?? 0" digitsInfo="1.2-3" [noFiat]="true"></app-amount> |               <app-amount [satoshis]="block.extras?.totalFees ?? 0" digitsInfo="1.2-3" [noFiat]="true"></app-amount> | ||||||
|             </div> |             </div> | ||||||
|  | |||||||
| @ -45,7 +45,10 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   markBlockSubscription: Subscription; |   markBlockSubscription: Subscription; | ||||||
|   txConfirmedSubscription: Subscription; |   txConfirmedSubscription: Subscription; | ||||||
|   loadingBlocks$: Observable<boolean>; |   loadingBlocks$: Observable<boolean>; | ||||||
|   showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); |   showMiningInfoSubscription: Subscription; | ||||||
|  |   blockDisplayModeSubscription: Subscription; | ||||||
|  |   blockDisplayMode: 'size' | 'fees'; | ||||||
|  |   blockTransformation = {}; | ||||||
|   blockStyles = []; |   blockStyles = []; | ||||||
|   emptyBlockStyles = []; |   emptyBlockStyles = []; | ||||||
|   interval: any; |   interval: any; | ||||||
| @ -78,22 +81,15 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   ) { |   ) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   enabledMiningInfoIfNeeded(url) { |  | ||||||
|     const urlParts = url.split('/'); |  | ||||||
|     const onDashboard = ['','testnet','signet','mining','acceleration'].includes(urlParts[urlParts.length - 1]); |  | ||||||
|     if (onDashboard) { // Only update showMiningInfo if we are on the main, mining or acceleration dashboards
 |  | ||||||
|       this.stateService.showMiningInfo$.next(url.includes('/mining') || url.includes('/acceleration')); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   ngOnInit() { |   ngOnInit() { | ||||||
|     this.dynamicBlocksAmount = Math.min(8, this.stateService.env.KEEP_BLOCKS_AMOUNT); |     this.dynamicBlocksAmount = Math.min(8, this.stateService.env.KEEP_BLOCKS_AMOUNT); | ||||||
| 
 | 
 | ||||||
|     if (['', 'testnet', 'signet'].includes(this.stateService.network)) { |     this.blockDisplayMode = this.stateService.blockDisplayMode$.value as 'size' | 'fees'; | ||||||
|       this.enabledMiningInfoIfNeeded(this.location.path()); |     this.blockDisplayModeSubscription = this.stateService.blockDisplayMode$.subscribe((mode: 'size' | 'fees') => { | ||||||
|       this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); |       if (mode !== this.blockDisplayMode) { | ||||||
|       this.showMiningInfo$ = this.stateService.showMiningInfo$; |         this.applyAnimation(mode); | ||||||
|       } |       } | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { |     this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { | ||||||
|       this.timeLtr = !!ltr; |       this.timeLtr = !!ltr; | ||||||
| @ -204,6 +200,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     this.networkSubscription.unsubscribe(); |     this.networkSubscription.unsubscribe(); | ||||||
|     this.tabHiddenSubscription.unsubscribe(); |     this.tabHiddenSubscription.unsubscribe(); | ||||||
|     this.markBlockSubscription.unsubscribe(); |     this.markBlockSubscription.unsubscribe(); | ||||||
|  |     this.blockDisplayModeSubscription.unsubscribe(); | ||||||
|     this.timeLtrSubscription.unsubscribe(); |     this.timeLtrSubscription.unsubscribe(); | ||||||
|     clearInterval(this.interval); |     clearInterval(this.interval); | ||||||
|   } |   } | ||||||
| @ -243,6 +240,29 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   applyAnimation(mode: 'size' | 'fees') { | ||||||
|  |     this.blockTransformation = this.timeLtr ? { | ||||||
|  |       transform: 'scaleX(-1) rotateX(90deg)', | ||||||
|  |       transition: 'transform 0.375s' | ||||||
|  |     } : { | ||||||
|  |       transform: 'rotateX(90deg)', | ||||||
|  |       transition: 'transform 0.375s' | ||||||
|  |     }; | ||||||
|  |     setTimeout(() => { | ||||||
|  |       this.blockDisplayMode = mode; | ||||||
|  |       this.blockTransformation = this.timeLtr ? { | ||||||
|  |         transform: 'scaleX(-1)', | ||||||
|  |         transition: 'transform 0.375s' | ||||||
|  |       } : { | ||||||
|  |         transition: 'transform 0.375s' | ||||||
|  |       }; | ||||||
|  |       this.cd.markForCheck(); | ||||||
|  |       setTimeout(() => { | ||||||
|  |         this.blockTransformation = {}; | ||||||
|  |       }, 375); | ||||||
|  |     }, 375); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   trackByBlocksFn(index: number, item: BlockchainBlock) { |   trackByBlocksFn(index: number, item: BlockchainBlock) { | ||||||
|     return item.height; |     return item.height; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
|         </ng-container> |         </ng-container> | ||||||
|       </div> |       </div> | ||||||
|       <div id="divider" [hidden]="pageIndex > 0"> |       <div id="divider" [hidden]="pageIndex > 0"> | ||||||
|  |         <button class="block-display-toggle" (click)="toggleBlockDisplayMode()"><fa-icon [icon]="['fas', 'exchange-alt']" [fixedWidth]="true"></fa-icon></button> | ||||||
|         <button class="time-toggle" (click)="toggleTimeDirection()"><fa-icon [icon]="['fas', 'exchange-alt']" [fixedWidth]="true"></fa-icon></button> |         <button class="time-toggle" (click)="toggleTimeDirection()"><fa-icon [icon]="['fas', 'exchange-alt']" [fixedWidth]="true"></fa-icon></button> | ||||||
|       </div> |       </div> | ||||||
|     </span> |     </span> | ||||||
|  | |||||||
| @ -67,9 +67,24 @@ | |||||||
|   padding: 0; |   padding: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .block-display-toggle { | ||||||
|  |   color: white; | ||||||
|  |   font-size: 0.8rem; | ||||||
|  |   position: absolute; | ||||||
|  |   bottom: 15.8em; | ||||||
|  |   left: 1px; | ||||||
|  |   transform: translateX(-50%) rotate(90deg); | ||||||
|  |   background: none; | ||||||
|  |   border: none; | ||||||
|  |   outline: none; | ||||||
|  |   margin: 0; | ||||||
|  |   padding: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .blockchain-wrapper.ltr-transition .blocks-wrapper, | .blockchain-wrapper.ltr-transition .blocks-wrapper, | ||||||
| .blockchain-wrapper.ltr-transition .position-container, | .blockchain-wrapper.ltr-transition .position-container, | ||||||
| .blockchain-wrapper.ltr-transition .time-toggle { | .blockchain-wrapper.ltr-transition .time-toggle, | ||||||
|  | .blockchain-wrapper.ltr-transition .block-display-toggle { | ||||||
|   transition: transform 1s; |   transition: transform 1s; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -81,6 +96,10 @@ | |||||||
|   .time-toggle { |   .time-toggle { | ||||||
|     transform: translateX(-50%) scaleX(-1); |     transform: translateX(-50%) scaleX(-1); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   .block-display-toggle { | ||||||
|  |     transform: translateX(-50%) scaleX(-1) rotate(90deg); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| :host-context(.ltr-layout) { | :host-context(.ltr-layout) { | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core'; | import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core'; | ||||||
| import { firstValueFrom, Subscription } from 'rxjs'; | import { firstValueFrom, Subscription } from 'rxjs'; | ||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
|  | import { StorageService } from '../../services/storage.service'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-blockchain', |   selector: 'app-blockchain', | ||||||
| @ -26,15 +27,18 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { | |||||||
|   connectionStateSubscription: Subscription; |   connectionStateSubscription: Subscription; | ||||||
|   loadingTip: boolean = true; |   loadingTip: boolean = true; | ||||||
|   connected: boolean = true; |   connected: boolean = true; | ||||||
|  |   blockDisplayMode: 'size' | 'fees'; | ||||||
| 
 | 
 | ||||||
|   dividerOffset: number | null = null; |   dividerOffset: number | null = null; | ||||||
|   mempoolOffset: number | null = null; |   mempoolOffset: number | null = null; | ||||||
|   positionStyle = { |   positionStyle = { | ||||||
|     transform: "translateX(1280px)", |     transform: "translateX(1280px)", | ||||||
|   }; |   }; | ||||||
|  |   blockDisplayToggleStyle = {}; | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     public stateService: StateService, |     public stateService: StateService, | ||||||
|  |     public StorageService: StorageService, | ||||||
|     private cd: ChangeDetectorRef, |     private cd: ChangeDetectorRef, | ||||||
|   ) {} |   ) {} | ||||||
| 
 | 
 | ||||||
| @ -51,6 +55,7 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { | |||||||
|     firstValueFrom(this.stateService.chainTip$).then(() => { |     firstValueFrom(this.stateService.chainTip$).then(() => { | ||||||
|       this.loadingTip = false; |       this.loadingTip = false; | ||||||
|     }); |     }); | ||||||
|  |     this.blockDisplayMode = this.StorageService.getValue('block-display-mode-preference') as 'size' | 'fees' || 'size'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ngOnDestroy(): void { |   ngOnDestroy(): void { | ||||||
| @ -84,6 +89,13 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { | |||||||
|     }, 0); |     }, 0); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   toggleBlockDisplayMode(): void { | ||||||
|  |     if (this.blockDisplayMode === 'size') this.blockDisplayMode = 'fees'; | ||||||
|  |     else this.blockDisplayMode = 'size'; | ||||||
|  |     this.StorageService.setValue('block-display-mode-preference', this.blockDisplayMode); | ||||||
|  |     this.stateService.blockDisplayMode$.next(this.blockDisplayMode); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   onMempoolWidthChange(width): void { |   onMempoolWidthChange(width): void { | ||||||
|     if (this.flipping) { |     if (this.flipping) { | ||||||
|       return; |       return; | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
|           class="spotlight-bottom" |           class="spotlight-bottom" | ||||||
|           [style.right]="mempoolBlockStyles[i].right" |           [style.right]="mempoolBlockStyles[i].right" | ||||||
|         ></div> |         ></div> | ||||||
|         <div @blockEntryTrigger [@.disabled]="i > 0 || !animateEntry" [attr.data-cy]="'mempool-block-' + i" class="bitcoin-block text-center mempool-block" [class.hide-block]="count && i >= count" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink"> |         <div @blockEntryTrigger [@.disabled]="i > 0 || !animateEntry" [attr.data-cy]="'mempool-block-' + i" class="bitcoin-block text-center mempool-block" [class.hide-block]="count && i >= count" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink" [style]="blockTransformation"> | ||||||
|           <a draggable="false" [routerLink]="[getHref(i) | relativeUrl]" |           <a draggable="false" [routerLink]="[getHref(i) | relativeUrl]" | ||||||
|             class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a> |             class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a> | ||||||
|           <div class="block-body"> |           <div class="block-body"> | ||||||
| @ -20,7 +20,7 @@ | |||||||
|                 - |                 - | ||||||
|                 <app-fee-rate [fee]="projectedBlock.feeRange[projectedBlock.feeRange.length - 1]" rounding="1.0-0" unitClass=""></app-fee-rate> |                 <app-fee-rate [fee]="projectedBlock.feeRange[projectedBlock.feeRange.length - 1]" rounding="1.0-0" unitClass=""></app-fee-rate> | ||||||
|               </div> |               </div> | ||||||
|               <div *ngIf="showMiningInfo$ | async; else noMiningInfo" class="block-size"> |               <div *ngIf="blockDisplayMode === 'fees'; else noMiningInfo" class="block-size"> | ||||||
|                 <app-amount [attr.data-cy]="'mempool-block-' + i + '-total-fees'" [satoshis]="projectedBlock.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount> |                 <app-amount [attr.data-cy]="'mempool-block-' + i + '-total-fees'" [satoshis]="projectedBlock.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount> | ||||||
|               </div> |               </div> | ||||||
|               <ng-template #noMiningInfo> |               <ng-template #noMiningInfo> | ||||||
|  | |||||||
| @ -43,7 +43,10 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   mempoolBlocks$: Observable<MempoolBlock[]>; |   mempoolBlocks$: Observable<MempoolBlock[]>; | ||||||
|   difficultyAdjustments$: Observable<DifficultyAdjustment>; |   difficultyAdjustments$: Observable<DifficultyAdjustment>; | ||||||
|   loadingBlocks$: Observable<boolean>; |   loadingBlocks$: Observable<boolean>; | ||||||
|   showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); |   showMiningInfoSubscription: Subscription; | ||||||
|  |   blockDisplayModeSubscription: Subscription; | ||||||
|  |   blockDisplayMode: 'size' | 'fees'; | ||||||
|  |   blockTransformation = {}; | ||||||
|   blocksSubscription: Subscription; |   blocksSubscription: Subscription; | ||||||
| 
 | 
 | ||||||
|   mempoolBlocksFull: MempoolBlock[] = []; |   mempoolBlocksFull: MempoolBlock[] = []; | ||||||
| @ -99,9 +102,12 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     this.mempoolWidth = width; |     this.mempoolWidth = width; | ||||||
|     this.widthChange.emit(this.mempoolWidth); |     this.widthChange.emit(this.mempoolWidth); | ||||||
| 
 | 
 | ||||||
|     if (['', 'testnet', 'signet'].includes(this.stateService.network)) { |     this.blockDisplayMode = this.stateService.blockDisplayMode$.value as 'size' | 'fees'; | ||||||
|       this.showMiningInfo$ = this.stateService.showMiningInfo$; |     this.blockDisplayModeSubscription = this.stateService.blockDisplayMode$.subscribe((mode: 'size' | 'fees') => { | ||||||
|  |       if (mode !== this.blockDisplayMode) { | ||||||
|  |         this.applyAnimation(mode); | ||||||
|       } |       } | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { |     this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { | ||||||
|       this.timeLtr = !this.forceRtl && !!ltr; |       this.timeLtr = !this.forceRtl && !!ltr; | ||||||
| @ -262,6 +268,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     this.markBlocksSubscription.unsubscribe(); |     this.markBlocksSubscription.unsubscribe(); | ||||||
|     this.blockSubscription.unsubscribe(); |     this.blockSubscription.unsubscribe(); | ||||||
|     this.networkSubscription.unsubscribe(); |     this.networkSubscription.unsubscribe(); | ||||||
|  |     this.blockDisplayModeSubscription.unsubscribe(); | ||||||
|     this.timeLtrSubscription.unsubscribe(); |     this.timeLtrSubscription.unsubscribe(); | ||||||
|     this.chainTipSubscription.unsubscribe(); |     this.chainTipSubscription.unsubscribe(); | ||||||
|     this.keySubscription.unsubscribe(); |     this.keySubscription.unsubscribe(); | ||||||
| @ -445,6 +452,23 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     this.rightPosition = Math.min(this.maxArrowPosition, this.rightPosition); |     this.rightPosition = Math.min(this.maxArrowPosition, this.rightPosition); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   applyAnimation(mode: 'size' | 'fees') { | ||||||
|  |     this.blockTransformation = { | ||||||
|  |       transform: 'rotateX(90deg)', | ||||||
|  |       transition: 'transform 0.375s' | ||||||
|  |     }; | ||||||
|  |     setTimeout(() => { | ||||||
|  |       this.blockDisplayMode = mode; | ||||||
|  |       this.blockTransformation = { | ||||||
|  |         transition: 'transform 0.375s' | ||||||
|  |       }; | ||||||
|  |       this.cd.markForCheck(); | ||||||
|  |       setTimeout(() => { | ||||||
|  |         this.blockTransformation = {}; | ||||||
|  |       }, 375); | ||||||
|  |     }, 375); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   mountEmptyBlocks() { |   mountEmptyBlocks() { | ||||||
|     const emptyBlocks = []; |     const emptyBlocks = []; | ||||||
|     const numberOfBlocks = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; |     const numberOfBlocks = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; | ||||||
|  | |||||||
| @ -151,7 +151,7 @@ export class StateService { | |||||||
|   hideAudit: BehaviorSubject<boolean>; |   hideAudit: BehaviorSubject<boolean>; | ||||||
|   fiatCurrency$: BehaviorSubject<string>; |   fiatCurrency$: BehaviorSubject<string>; | ||||||
|   rateUnits$: BehaviorSubject<string>; |   rateUnits$: BehaviorSubject<string>; | ||||||
|   showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); |   blockDisplayMode$: BehaviorSubject<string> = new BehaviorSubject<string>('size'); | ||||||
| 
 | 
 | ||||||
|   searchFocus$: Subject<boolean> = new Subject<boolean>(); |   searchFocus$: Subject<boolean> = new Subject<boolean>(); | ||||||
|   menuOpen$: BehaviorSubject<boolean> = new BehaviorSubject(false); |   menuOpen$: BehaviorSubject<boolean> = new BehaviorSubject(false); | ||||||
| @ -259,6 +259,9 @@ export class StateService { | |||||||
|     const rateUnitPreference = this.storageService.getValue('rate-unit-preference'); |     const rateUnitPreference = this.storageService.getValue('rate-unit-preference'); | ||||||
|     this.rateUnits$ = new BehaviorSubject<string>(rateUnitPreference || 'vb'); |     this.rateUnits$ = new BehaviorSubject<string>(rateUnitPreference || 'vb'); | ||||||
| 
 | 
 | ||||||
|  |     const blockDisplayModePreference = this.storageService.getValue('block-display-mode-preference'); | ||||||
|  |     this.blockDisplayMode$ = new BehaviorSubject<string>(blockDisplayModePreference || 'size'); | ||||||
|  | 
 | ||||||
|     this.backend$.subscribe(backend => { |     this.backend$.subscribe(backend => { | ||||||
|       this.backend = backend; |       this.backend = backend; | ||||||
|     }); |     }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user