diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html
index ac29524bb..603c7e4c0 100644
--- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html
+++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html
@@ -12,6 +12,7 @@
class="text-center bitcoin-block mined-block blockchain-blocks-offset-{{ offset }}-index-{{ i }}"
[class.offscreen]="!static && count && i >= count"
id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]"
+ [style]="blockTransformation"
[class.blink-bg]="isSpecial(block.height)">
@@ -40,7 +41,7 @@
-
diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts
index ca79b68a6..35499f162 100644
--- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts
+++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts
@@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input, OnChanges, SimpleChanges } from '@angular/core';
-import { BehaviorSubject, Observable, Subscription } from 'rxjs';
+import { Observable, Subscription, delay, filter, tap } from 'rxjs';
import { StateService } from '../../services/state.service';
import { specialBlocks } from '../../app.constants';
import { BlockExtended } from '../../interfaces/node-api.interface';
@@ -45,7 +45,10 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
markBlockSubscription: Subscription;
txConfirmedSubscription: Subscription;
loadingBlocks$: Observable;
- showMiningInfo$: BehaviorSubject = new BehaviorSubject(false);
+ showMiningInfoSubscription: Subscription;
+ blockDisplayModeSubscription: Subscription;
+ blockDisplayMode: 'size' | 'fees';
+ blockTransformation = {};
blockStyles = [];
emptyBlockStyles = [];
interval: any;
@@ -78,22 +81,38 @@ 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() {
this.dynamicBlocksAmount = Math.min(8, this.stateService.env.KEEP_BLOCKS_AMOUNT);
- if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
- this.enabledMiningInfoIfNeeded(this.location.path());
- this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url));
- this.showMiningInfo$ = this.stateService.showMiningInfo$;
- }
+ this.blockDisplayMode = this.stateService.blockDisplayMode$.value as 'size' | 'fees';
+ this.blockDisplayModeSubscription = this.stateService.blockDisplayMode$
+ .pipe(
+ filter((mode: 'size' | 'fees') => mode !== this.blockDisplayMode),
+ tap(() => {
+ this.blockTransformation = this.timeLtr ? {
+ transform: 'scaleX(-1) rotateX(90deg)',
+ transition: 'transform 0.375s'
+ } : {
+ transform: 'rotateX(90deg)',
+ transition: 'transform 0.375s'
+ };
+ }),
+ delay(375),
+ tap((mode) => {
+ this.blockDisplayMode = mode;
+ this.blockTransformation = this.timeLtr ? {
+ transform: 'scaleX(-1)',
+ transition: 'transform 0.375s'
+ } : {
+ transition: 'transform 0.375s'
+ };
+ this.cd.markForCheck();
+ }),
+ delay(375),
+ )
+ .subscribe(() => {
+ this.blockTransformation = {};
+ });
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !!ltr;
@@ -204,6 +223,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
this.networkSubscription.unsubscribe();
this.tabHiddenSubscription.unsubscribe();
this.markBlockSubscription.unsubscribe();
+ this.blockDisplayModeSubscription.unsubscribe();
this.timeLtrSubscription.unsubscribe();
clearInterval(this.interval);
}
diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html
index 5f625e4b3..af3bf52b1 100644
--- a/frontend/src/app/components/blockchain/blockchain.component.html
+++ b/frontend/src/app/components/blockchain/blockchain.component.html
@@ -10,6 +10,7 @@
0">
+
diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss
index a8ecc6aba..b0a589a04 100644
--- a/frontend/src/app/components/blockchain/blockchain.component.scss
+++ b/frontend/src/app/components/blockchain/blockchain.component.scss
@@ -67,9 +67,24 @@
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 .position-container,
-.blockchain-wrapper.ltr-transition .time-toggle {
+.blockchain-wrapper.ltr-transition .time-toggle,
+.blockchain-wrapper.ltr-transition .block-display-toggle {
transition: transform 1s;
}
@@ -81,6 +96,10 @@
.time-toggle {
transform: translateX(-50%) scaleX(-1);
}
+
+ .block-display-toggle {
+ transform: translateX(-50%) scaleX(-1) rotate(90deg);
+ }
}
:host-context(.ltr-layout) {
diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts
index 2293b9479..60dc22e12 100644
--- a/frontend/src/app/components/blockchain/blockchain.component.ts
+++ b/frontend/src/app/components/blockchain/blockchain.component.ts
@@ -1,6 +1,7 @@
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
import { firstValueFrom, Subscription } from 'rxjs';
import { StateService } from '../../services/state.service';
+import { StorageService } from '../../services/storage.service';
@Component({
selector: 'app-blockchain',
@@ -26,15 +27,18 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges {
connectionStateSubscription: Subscription;
loadingTip: boolean = true;
connected: boolean = true;
+ blockDisplayMode: 'size' | 'fees';
dividerOffset: number | null = null;
mempoolOffset: number | null = null;
positionStyle = {
transform: "translateX(1280px)",
};
+ blockDisplayToggleStyle = {};
constructor(
public stateService: StateService,
+ public StorageService: StorageService,
private cd: ChangeDetectorRef,
) {}
@@ -51,6 +55,7 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges {
firstValueFrom(this.stateService.chainTip$).then(() => {
this.loadingTip = false;
});
+ this.blockDisplayMode = this.StorageService.getValue('block-display-mode-preference') as 'size' | 'fees' || 'size';
}
ngOnDestroy(): void {
@@ -84,6 +89,13 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges {
}, 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 {
if (this.flipping) {
return;
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 aa2043af2..24f229598 100644
--- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html
+++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html
@@ -7,7 +7,7 @@
class="spotlight-bottom"
[style.right]="mempoolBlockStyles[i].right"
>
- 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">
+
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">
-
+
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 f403eac71..dee770cd8 100644
--- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts
+++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts
@@ -1,9 +1,9 @@
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
-import { Subscription, Observable, of, combineLatest, BehaviorSubject } from 'rxjs';
+import { Subscription, Observable, of, combineLatest } from 'rxjs';
import { MempoolBlock } from '../../interfaces/websocket.interface';
import { StateService } from '../../services/state.service';
import { Router } from '@angular/router';
-import { map, switchMap, tap } from 'rxjs/operators';
+import { delay, filter, map, switchMap, tap } from 'rxjs/operators';
import { feeLevels } from '../../app.constants';
import { specialBlocks } from '../../app.constants';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
@@ -43,7 +43,10 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
mempoolBlocks$: Observable;
difficultyAdjustments$: Observable;
loadingBlocks$: Observable;
- showMiningInfo$: BehaviorSubject = new BehaviorSubject(false);
+ showMiningInfoSubscription: Subscription;
+ blockDisplayModeSubscription: Subscription;
+ blockDisplayMode: 'size' | 'fees';
+ blockTransformation = {};
blocksSubscription: Subscription;
mempoolBlocksFull: MempoolBlock[] = [];
@@ -99,9 +102,29 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
this.mempoolWidth = width;
this.widthChange.emit(this.mempoolWidth);
- if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
- this.showMiningInfo$ = this.stateService.showMiningInfo$;
- }
+ this.blockDisplayMode = this.stateService.blockDisplayMode$.value as 'size' | 'fees';
+ this.blockDisplayModeSubscription = this.stateService.blockDisplayMode$
+ .pipe(
+ filter((mode: 'size' | 'fees') => mode !== this.blockDisplayMode),
+ tap(() => {
+ this.blockTransformation = {
+ transform: 'rotateX(90deg)',
+ transition: 'transform 0.375s'
+ };
+ }),
+ delay(375),
+ tap((mode) => {
+ this.blockDisplayMode = mode;
+ this.blockTransformation = {
+ transition: 'transform 0.375s'
+ };
+ this.cd.markForCheck();
+ }),
+ delay(375),
+ )
+ .subscribe(() => {
+ this.blockTransformation = {};
+ });
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !this.forceRtl && !!ltr;
@@ -262,6 +285,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
this.markBlocksSubscription.unsubscribe();
this.blockSubscription.unsubscribe();
this.networkSubscription.unsubscribe();
+ this.blockDisplayModeSubscription.unsubscribe();
this.timeLtrSubscription.unsubscribe();
this.chainTipSubscription.unsubscribe();
this.keySubscription.unsubscribe();
diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts
index 970bfcac3..ebc4786d1 100644
--- a/frontend/src/app/services/state.service.ts
+++ b/frontend/src/app/services/state.service.ts
@@ -151,7 +151,7 @@ export class StateService {
hideAudit: BehaviorSubject;
fiatCurrency$: BehaviorSubject;
rateUnits$: BehaviorSubject;
- showMiningInfo$: BehaviorSubject = new BehaviorSubject(false);
+ blockDisplayMode$: BehaviorSubject = new BehaviorSubject('size');
searchFocus$: Subject = new Subject();
menuOpen$: BehaviorSubject = new BehaviorSubject(false);
@@ -259,6 +259,9 @@ export class StateService {
const rateUnitPreference = this.storageService.getValue('rate-unit-preference');
this.rateUnits$ = new BehaviorSubject(rateUnitPreference || 'vb');
+ const blockDisplayModePreference = this.storageService.getValue('block-display-mode-preference');
+ this.blockDisplayMode$ = new BehaviorSubject(blockDisplayModePreference || 'size');
+
this.backend$.subscribe(backend => {
this.backend = backend;
});