Redesign difficulty adjustment dashboard widget
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
<div *ngIf="showTitle" class="main-title" i18n="dashboard.difficulty-adjustment">Difficulty Adjustment</div>
|
||||
<div class="card-wrapper">
|
||||
<div class="card">
|
||||
<div class="card-body more-padding">
|
||||
<div class="difficulty-adjustment-container" *ngIf="(isLoadingWebSocket$ | async) === false && (difficultyEpoch$ | async) as epochData; else loadingDifficulty">
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.remaining">Remaining</h5>
|
||||
<div class="card-text">
|
||||
<ng-container *ngTemplateOutlet="epochData.remainingBlocks === 1 ? blocksSingular : blocksPlural; context: {$implicit: epochData.remainingBlocks }"></ng-container>
|
||||
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
||||
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} <span class="shared-block">block</span></ng-template>
|
||||
</div>
|
||||
<div class="symbol"><app-time kind="until" [time]="epochData.estimatedRetargetDate" [fastRender]="true"></app-time></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.estimate">Estimate</h5>
|
||||
<div *ngIf="epochData.remainingBlocks < 1870; else recentlyAdjusted" class="card-text" [ngStyle]="{'color': epochData.colorAdjustments}">
|
||||
<span *ngIf="epochData.change > 0; else arrowDownDifficulty" >
|
||||
<fa-icon class="retarget-sign" [icon]="['fas', 'caret-up']" [fixedWidth]="true"></fa-icon>
|
||||
</span>
|
||||
<ng-template #arrowDownDifficulty >
|
||||
<fa-icon class="retarget-sign" [icon]="['fas', 'caret-down']" [fixedWidth]="true"></fa-icon>
|
||||
</ng-template>
|
||||
{{ epochData.change | absolute | number: '1.2-2' }}
|
||||
<span class="symbol">%</span>
|
||||
</div>
|
||||
<ng-template #recentlyAdjusted>
|
||||
<div class="card-text">—</div>
|
||||
</ng-template>
|
||||
<div class="symbol">
|
||||
<span i18n="difficulty-box.previous">Previous</span>:
|
||||
<span [ngStyle]="{'color': epochData.colorPreviousAdjustments}">
|
||||
<span *ngIf="epochData.previousRetarget > 0; else arrowDownPreviousDifficulty" >
|
||||
<fa-icon class="previous-retarget-sign" [icon]="['fas', 'caret-up']" [fixedWidth]="true"></fa-icon>
|
||||
</span>
|
||||
<ng-template #arrowDownPreviousDifficulty >
|
||||
<fa-icon class="previous-retarget-sign" [icon]="['fas', 'caret-down']" [fixedWidth]="true"></fa-icon>
|
||||
</ng-template>
|
||||
{{ epochData.previousRetarget | absolute | number: '1.2-2' }} </span> %
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" *ngIf="showProgress">
|
||||
<h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5>
|
||||
<div class="card-text">{{ epochData.progress | number: '1.2-2' }} <span class="symbol">%</span></div>
|
||||
<div class="progress small-bar">
|
||||
<div class="progress-bar" role="progressbar" style="width: 15%; background-color: #105fb0" [ngStyle]="{'width': epochData.base}"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item" *ngIf="showHalving">
|
||||
<h5 class="card-title" i18n="difficulty-box.next-halving">Next Halving</h5>
|
||||
<div class="card-text">
|
||||
<ng-container *ngTemplateOutlet="epochData.blocksUntilHalving === 1 ? blocksSingular : blocksPlural; context: {$implicit: epochData.blocksUntilHalving }"></ng-container>
|
||||
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
||||
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} <span class="shared-block">block</span></ng-template>
|
||||
</div>
|
||||
<div class="symbol"><app-time kind="until" [time]="epochData.timeUntilHalving" [fastRender]="true"></app-time></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #loadingDifficulty>
|
||||
<div class="difficulty-skeleton loading-container">
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.remaining">Remaining</h5>
|
||||
<div class="card-text">
|
||||
<div class="skeleton-loader"></div>
|
||||
<div class="skeleton-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.estimate">Estimate</h5>
|
||||
<div class="card-text">
|
||||
<div class="skeleton-loader"></div>
|
||||
<div class="skeleton-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5>
|
||||
<div class="card-text">
|
||||
<div class="skeleton-loader"></div>
|
||||
<div class="skeleton-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,154 @@
|
||||
.difficulty-adjustment-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
height: 76px;
|
||||
.shared-block {
|
||||
color: #ffffff66;
|
||||
font-size: 12px;
|
||||
}
|
||||
.item {
|
||||
padding: 0 5px;
|
||||
width: 100%;
|
||||
&:nth-child(1) {
|
||||
display: none;
|
||||
@media (min-width: 485px) {
|
||||
display: table-cell;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
.card-text {
|
||||
font-size: 22px;
|
||||
margin-top: -9px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.difficulty-skeleton {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@media (min-width: 376px) {
|
||||
flex-direction: row;
|
||||
}
|
||||
.item {
|
||||
max-width: 150px;
|
||||
margin: 0;
|
||||
width: -webkit-fill-available;
|
||||
@media (min-width: 376px) {
|
||||
margin: 0 auto 0px;
|
||||
}
|
||||
&:first-child{
|
||||
display: none;
|
||||
@media (min-width: 485px) {
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.card-text {
|
||||
.skeleton-loader {
|
||||
width: 100%;
|
||||
display: block;
|
||||
&:first-child {
|
||||
margin: 14px auto 0;
|
||||
max-width: 80px;
|
||||
}
|
||||
&:last-child {
|
||||
margin: 10px auto 0;
|
||||
max-width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #1d1f31;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
color: #4a68b9;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.progress {
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
background-color: #2d3348;
|
||||
height: 1.1rem;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.skeleton-loader {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.more-padding {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.small-bar {
|
||||
height: 8px;
|
||||
top: -4px;
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
min-height: 76px;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
position: relative;
|
||||
color: #ffffff91;
|
||||
margin-top: -13px;
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.card-wrapper {
|
||||
.card {
|
||||
height: auto !important;
|
||||
}
|
||||
.card-body {
|
||||
display: flex;
|
||||
flex: inherit;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.retarget-sign {
|
||||
margin-right: -3px;
|
||||
font-size: 14px;
|
||||
top: -2px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.previous-retarget-sign {
|
||||
margin-right: -2px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.symbol {
|
||||
font-size: 13px;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { combineLatest, Observable, timer } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { StateService } from '../../services/state.service';
|
||||
|
||||
interface EpochProgress {
|
||||
base: string;
|
||||
change: number;
|
||||
progress: number;
|
||||
remainingBlocks: number;
|
||||
newDifficultyHeight: number;
|
||||
colorAdjustments: string;
|
||||
colorPreviousAdjustments: string;
|
||||
estimatedRetargetDate: number;
|
||||
previousRetarget: number;
|
||||
blocksUntilHalving: number;
|
||||
timeUntilHalving: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-difficulty-mining',
|
||||
templateUrl: './difficulty-mining.component.html',
|
||||
styleUrls: ['./difficulty-mining.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DifficultyMiningComponent implements OnInit {
|
||||
isLoadingWebSocket$: Observable<boolean>;
|
||||
difficultyEpoch$: Observable<EpochProgress>;
|
||||
|
||||
@Input() showProgress = true;
|
||||
@Input() showHalving = false;
|
||||
@Input() showTitle = true;
|
||||
|
||||
constructor(
|
||||
public stateService: StateService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
|
||||
this.difficultyEpoch$ = combineLatest([
|
||||
this.stateService.blocks$.pipe(map(([block]) => block)),
|
||||
this.stateService.difficultyAdjustment$,
|
||||
])
|
||||
.pipe(
|
||||
map(([block, da]) => {
|
||||
let colorAdjustments = '#ffffff66';
|
||||
if (da.difficultyChange > 0) {
|
||||
colorAdjustments = '#3bcc49';
|
||||
}
|
||||
if (da.difficultyChange < 0) {
|
||||
colorAdjustments = '#dc3545';
|
||||
}
|
||||
|
||||
let colorPreviousAdjustments = '#dc3545';
|
||||
if (da.previousRetarget) {
|
||||
if (da.previousRetarget >= 0) {
|
||||
colorPreviousAdjustments = '#3bcc49';
|
||||
}
|
||||
if (da.previousRetarget === 0) {
|
||||
colorPreviousAdjustments = '#ffffff66';
|
||||
}
|
||||
} else {
|
||||
colorPreviousAdjustments = '#ffffff66';
|
||||
}
|
||||
|
||||
const blocksUntilHalving = 210000 - (block.height % 210000);
|
||||
const timeUntilHalving = new Date().getTime() + (blocksUntilHalving * 600000);
|
||||
|
||||
const data = {
|
||||
base: `${da.progressPercent.toFixed(2)}%`,
|
||||
change: da.difficultyChange,
|
||||
progress: da.progressPercent,
|
||||
remainingBlocks: da.remainingBlocks - 1,
|
||||
colorAdjustments,
|
||||
colorPreviousAdjustments,
|
||||
newDifficultyHeight: da.nextRetargetHeight,
|
||||
estimatedRetargetDate: da.estimatedRetargetDate,
|
||||
previousRetarget: da.previousRetarget,
|
||||
blocksUntilHalving,
|
||||
timeUntilHalving,
|
||||
};
|
||||
return data;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user