Reversible blockchain components

This commit is contained in:
Mononaut 2022-09-29 22:45:40 +00:00
parent 135fbfc4f3
commit d07bf30737
No known key found for this signature in database
GPG Key ID: 61B952CAF4838F94
9 changed files with 130 additions and 25 deletions

View File

@ -1,4 +1,4 @@
<div class="blocks-container blockchain-blocks-container" *ngIf="(loadingBlocks$ | async) === false; else loadingBlocksTemplate"> <div class="blocks-container blockchain-blocks-container" [class.time-ltr]="timeLtr" *ngIf="(loadingBlocks$ | async) === false; else loadingBlocksTemplate">
<div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" > <div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
<div [attr.data-cy]="'bitcoin-block-' + i" class="text-center bitcoin-block mined-block blockchain-blocks-{{ i }}" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" [class.blink-bg]="(specialBlocks[block.height] !== undefined)"> <div [attr.data-cy]="'bitcoin-block-' + i" class="text-center bitcoin-block mined-block blockchain-blocks-{{ i }}" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" [class.blink-bg]="(specialBlocks[block.height] !== undefined)">
<a draggable="false" [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }" <a draggable="false" [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }"
@ -34,7 +34,7 @@
</div> </div>
<ng-template #loadingBlocksTemplate> <ng-template #loadingBlocksTemplate>
<div class="blocks-container"> <div class="blocks-container" [class.time-ltr]="timeLtr">
<div class="flashing"> <div class="flashing">
<div *ngFor="let block of emptyBlocks; let i = index; trackBy: trackByBlocksFn" > <div *ngFor="let block of emptyBlocks; let i = index; trackBy: trackByBlocksFn" >
<div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}" [ngStyle]="emptyBlockStyles[i]"></div> <div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}" [ngStyle]="emptyBlockStyles[i]"></div>

View File

@ -22,7 +22,7 @@
.mined-block { .mined-block {
position: absolute; position: absolute;
top: 0px; top: 0px;
transition: 2s; transition: background 2s, left 2s, transform 1s;
} }
.block-size { .block-size {
@ -34,6 +34,7 @@
position: absolute; position: absolute;
top: 0px; top: 0px;
left: 40px; left: 40px;
transition: left 2s;
} }
.block-body { .block-body {
@ -145,3 +146,9 @@
opacity: 0; opacity: 0;
pointer-events : none; pointer-events : none;
} }
.time-ltr {
.bitcoin-block {
transform: scaleX(-1);
}
}

View File

@ -33,6 +33,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
blocksFilled = false; blocksFilled = false;
transition = '1s'; transition = '1s';
showMiningInfo = false; showMiningInfo = false;
timeLtrSubscription: Subscription;
timeLtr: boolean;
gradientColors = { gradientColors = {
'': ['#9339f4', '#105fb0'], '': ['#9339f4', '#105fb0'],
@ -61,6 +63,11 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url)); this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url));
} }
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !!ltr;
this.cd.markForCheck();
});
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
this.feeRounding = '1.0-1'; this.feeRounding = '1.0-1';
} }
@ -123,6 +130,7 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
this.networkSubscription.unsubscribe(); this.networkSubscription.unsubscribe();
this.tabHiddenSubscription.unsubscribe(); this.tabHiddenSubscription.unsubscribe();
this.markBlockSubscription.unsubscribe(); this.markBlockSubscription.unsubscribe();
this.timeLtrSubscription.unsubscribe();
clearInterval(this.interval); clearInterval(this.interval);
} }

View File

@ -1,9 +1,13 @@
<div class="text-center" class="blockchain-wrapper" #container> <div class="text-center" class="blockchain-wrapper" [class.time-ltr]="timeLtr" [class.ltr-transition]="ltrTransitionEnabled" #container>
<div class="position-container {{ network }}"> <div class="position-container" [class]="['position-container']">
<span> <span>
<app-mempool-blocks></app-mempool-blocks> <div class="blocks-wrapper">
<app-blockchain-blocks></app-blockchain-blocks> <app-mempool-blocks></app-mempool-blocks>
<div id="divider"></div> <app-blockchain-blocks></app-blockchain-blocks>
</div>
<div id="divider">
<button class="time-toggle" (click)="toggleTimeDirection()"><fa-icon [icon]="['fas', 'arrows-rotate']" [fixedWidth]="true"></fa-icon></button>
</div>
</span> </span>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@
.blockchain-wrapper { .blockchain-wrapper {
height: 250px; height: 250px;
-webkit-user-select: none; /* Safari */ -webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */ -moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */ -ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard */ user-select: none; /* Standard */
@ -24,23 +24,46 @@
.position-container { .position-container {
position: absolute; position: absolute;
left: 50%; left: 0;
top: 75px; top: 75px;
transform: translateX(50vw);
transition: transform 1s;
} }
.position-container.liquid, .position-container.liquidtestnet { .position-container.liquid, .position-container.liquidtestnet {
left: 420px; transform: translateX(420px);
}
@media (min-width: 768px) {
.blockchain-wrapper.time-ltr {
.position-container.liquid, .position-container.liquidtestnet {
transform: translateX(calc(100vw - 420px));
}
}
} }
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.position-container { .blockchain-wrapper {
left: 95%; .position-container {
transform: translateX(95vw);
}
.position-container.liquid, .position-container.liquidtestnet {
transform: translateX(50vw);
}
.position-container.loading {
transform: translateX(50vw);
}
} }
.position-container.liquid, .position-container.liquidtestnet { .blockchain-wrapper.time-ltr {
left: 50%; .position-container {
} transform: translateX(5vw);
.position-container.loading { }
left: 50%; .position-container.liquid, .position-container.liquidtestnet {
transform: translateX(50vw);
}
.position-container.loading {
transform: translateX(50vw);
}
} }
} }
@ -57,4 +80,31 @@
width: 300px; width: 300px;
left: -150px; left: -150px;
top: 0px; top: 0px;
}
.time-toggle {
color: white;
font-size: 1rem;
position: absolute;
bottom: -1.5em;
left: 1px;
transform: translateX(-50%);
background: none;
border: none;
outline: none;
margin: 0;
padding: 0;
transition: transform 1s;
}
.blockchain-wrapper.ltr-transition .blocks-wrapper {
transition: transform 1s;
}
.blockchain-wrapper.time-ltr .blocks-wrapper {
transform: scaleX(-1);
}
.blockchain-wrapper.time-ltr .time-toggle {
transform: translateX(-50%) scaleX(-1);
} }

View File

@ -1,4 +1,5 @@
import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
import { Subscription } from 'rxjs';
import { StateService } from '../../services/state.service'; import { StateService } from '../../services/state.service';
@Component({ @Component({
@ -7,8 +8,11 @@ import { StateService } from '../../services/state.service';
styleUrls: ['./blockchain.component.scss'], styleUrls: ['./blockchain.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class BlockchainComponent implements OnInit { export class BlockchainComponent implements OnInit, OnDestroy {
network: string; network: string;
timeLtrSubscription: Subscription;
timeLtr: boolean = this.stateService.timeLtr.value;
ltrTransitionEnabled = false;
constructor( constructor(
public stateService: StateService, public stateService: StateService,
@ -16,5 +20,17 @@ export class BlockchainComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.network = this.stateService.network; this.network = this.stateService.network;
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !!ltr;
});
}
ngOnDestroy() {
this.timeLtrSubscription.unsubscribe();
}
toggleTimeDirection() {
this.ltrTransitionEnabled = true;
this.stateService.timeLtr.next(!this.timeLtr);
} }
} }

View File

@ -1,5 +1,5 @@
<ng-container *ngIf="(loadingBlocks$ | async) === false; else loadingBlocks"> <ng-container *ngIf="(loadingBlocks$ | async) === false; else loadingBlocks">
<div class="mempool-blocks-container" *ngIf="(difficultyAdjustments$ | async) as da;"> <div class="mempool-blocks-container" [class.time-ltr]="timeLtr" *ngIf="(difficultyAdjustments$ | async) as da;">
<div class="flashing"> <div class="flashing">
<ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn"> <ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn">
<div [attr.data-cy]="'mempool-block-' + i" class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink"> <div [attr.data-cy]="'mempool-block-' + i" class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink">
@ -45,7 +45,7 @@
</ng-container> </ng-container>
<ng-template #loadingBlocks> <ng-template #loadingBlocks>
<div class="mempool-blocks-container"> <div class="mempool-blocks-container" [class.time-ltr]="timeLtr">
<div class="flashing"> <div class="flashing">
<ng-template ngFor let-projectedBlock [ngForOf]="mempoolEmptyBlocks" let-i="index" [ngForTrackBy]="trackByFn"> <ng-template ngFor let-projectedBlock [ngForOf]="mempoolEmptyBlocks" let-i="index" [ngForTrackBy]="trackByFn">
<div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolEmptyBlockStyles[i]"></div> <div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolEmptyBlockStyles[i]"></div>

View File

@ -1,7 +1,7 @@
.bitcoin-block { .bitcoin-block {
width: 125px; width: 125px;
height: 125px; height: 125px;
transition: 2s; transition: background 2s, right 2s, transform 1s;
} }
.block-size { .block-size {
@ -33,6 +33,7 @@
.block-body { .block-body {
text-align: center; text-align: center;
transition: transform 1s;
} }
@keyframes opacityPulse { @keyframes opacityPulse {
@ -73,6 +74,7 @@
background-color: #232838; background-color: #232838;
transform:skew(40deg); transform:skew(40deg);
transform-origin:top; transform-origin:top;
transition: transform 1s, left 1s;
} }
.bitcoin-block::before { .bitcoin-block::before {
@ -83,9 +85,11 @@
top: -12px; top: -12px;
left: -20px; left: -20px;
background-color: #191c27; background-color: #191c27;
z-index: -1;
transform: skewY(50deg); transform: skewY(50deg);
transform-origin: top; transform-origin: top;
transition: transform 1s, left 1s;
} }
.mempool-block.bitcoin-block::after { .mempool-block.bitcoin-block::after {
@ -128,3 +132,18 @@
.blockLink:hover { .blockLink:hover {
text-decoration: none; text-decoration: none;
} }
.time-ltr {
.bitcoin-block::after {
transform: skew(-40deg);
left: 20px;
}
.bitcoin-block::before {
transform: skewY(-50deg);
left: 125px;
}
.block-body {
transform: scaleX(-1);
}
}

View File

@ -46,7 +46,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
feeRounding = '1.0-0'; feeRounding = '1.0-0';
rightPosition = 0; rightPosition = 0;
transition = '2s'; transition = 'background 2s, right 2s, transform 1s';
markIndex: number; markIndex: number;
txFeePerVSize: number; txFeePerVSize: number;
@ -76,6 +76,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
this.timeLtr = !!ltr; this.timeLtr = !!ltr;
this.cd.markForCheck();
}); });
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
@ -278,7 +279,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
this.arrowVisible = true; this.arrowVisible = true;
this.resetTransitionTimeout = window.setTimeout(() => { this.resetTransitionTimeout = window.setTimeout(() => {
this.transition = '2s'; this.transition = 'background 2s, right 2s, transform 1s';
this.cd.markForCheck(); this.cd.markForCheck();
}, 100); }, 100);
return; return;