mirror of
https://github.com/mempool/mempool.git
synced 2025-04-28 05:12:05 +02:00
Merge pull request #2594 from mononaut/turn-back-time
Add a time turner toggle
This commit is contained in:
commit
6e235924d8
@ -1,4 +1,4 @@
|
|||||||
import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy } from '@angular/core';
|
import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy, OnChanges } from '@angular/core';
|
||||||
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
||||||
import { FastVertexArray } from './fast-vertex-array';
|
import { FastVertexArray } from './fast-vertex-array';
|
||||||
import BlockScene from './block-scene';
|
import BlockScene from './block-scene';
|
||||||
@ -11,7 +11,7 @@ import { Position } from './sprite-types';
|
|||||||
templateUrl: './block-overview-graph.component.html',
|
templateUrl: './block-overview-graph.component.html',
|
||||||
styleUrls: ['./block-overview-graph.component.scss'],
|
styleUrls: ['./block-overview-graph.component.scss'],
|
||||||
})
|
})
|
||||||
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
|
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges {
|
||||||
@Input() isLoading: boolean;
|
@Input() isLoading: boolean;
|
||||||
@Input() resolution: number;
|
@Input() resolution: number;
|
||||||
@Input() blockLimit: number;
|
@Input() blockLimit: number;
|
||||||
@ -57,6 +57,14 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
|
|||||||
this.resizeCanvas();
|
this.resizeCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes): void {
|
||||||
|
if (changes.orientation || changes.flip) {
|
||||||
|
if (this.scene) {
|
||||||
|
this.scene.setOrientation(this.orientation, this.flip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.animationFrameRequest) {
|
if (this.animationFrameRequest) {
|
||||||
cancelAnimationFrame(this.animationFrameRequest);
|
cancelAnimationFrame(this.animationFrameRequest);
|
||||||
|
@ -42,6 +42,15 @@ export default class BlockScene {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOrientation(orientation: string, flip: boolean): void {
|
||||||
|
this.orientation = orientation;
|
||||||
|
this.flip = flip;
|
||||||
|
this.dirty = true;
|
||||||
|
if (this.initialised && this.scene) {
|
||||||
|
this.updateAll(performance.now(), 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Destroy the current layout and clean up graphics sprites without any exit animation
|
// Destroy the current layout and clean up graphics sprites without any exit animation
|
||||||
destroy(): void {
|
destroy(): void {
|
||||||
Object.values(this.txs).forEach(tx => tx.destroy());
|
Object.values(this.txs).forEach(tx => tx.destroy());
|
||||||
|
@ -1,36 +1,24 @@
|
|||||||
<div class="container-xl" (window:resize)="onResize($event)">
|
<div class="container-xl" (window:resize)="onResize($event)">
|
||||||
|
|
||||||
<div class="title-block" id="block">
|
<div class="title-block" [class.time-ltr]="timeLtr" id="block">
|
||||||
<h1>
|
<h1>
|
||||||
<ng-template [ngIf]="blockHeight === 0"><ng-container i18n="@@2303359202781425764">Genesis</ng-container>
|
<ng-container *ngIf="blockHeight > 0; else genesis" i18n="shared.block-title">Block</ng-container>
|
||||||
|
<ng-template #genesis i18n="@@2303359202781425764">Genesis</ng-template>
|
||||||
<span class="next-previous-blocks">
|
<span class="next-previous-blocks">
|
||||||
<a *ngIf="showNextBlocklink" [routerLink]="['/block/' | relativeUrl, nextBlockHeight]" (click)="navigateToNextBlock()" i18n-ngbTooltip="Next Block" ngbTooltip="Next Block" placement="bottom">
|
<a *ngIf="showNextBlocklink" class="nav-arrow next" [routerLink]="['/block/' | relativeUrl, nextBlockHeight]" (click)="navigateToNextBlock()" i18n-ngbTooltip="Next Block" ngbTooltip="Next Block" placement="bottom">
|
||||||
<fa-icon [icon]="['fas', 'angle-left']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'angle-left']" [fixedWidth]="true"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
<a [routerLink]="['/block/' | relativeUrl, blockHash]">{{ blockHeight }}</a>
|
<span *ngIf="!showNextBlocklink" placement="bottom" class="disable nav-arrow next">
|
||||||
<span placement="bottom" class="disable">
|
<fa-icon [icon]="['fas', 'angle-left']" [fixedWidth]="true"></fa-icon>
|
||||||
|
</span>
|
||||||
|
<a [routerLink]="['/block/' | relativeUrl, blockHash]" class="block-link">{{ blockHeight }}</a>
|
||||||
|
<a *ngIf="showPreviousBlocklink && block" class="nav-arrow prev" [routerLink]="['/block/' | relativeUrl, block.previousblockhash]" (click)="navigateToPreviousBlock()" i18n-ngbTooltip="Previous Block" ngbTooltip="Previous Block" placement="bottom">
|
||||||
|
<fa-icon [icon]="['fas', 'angle-right']" [fixedWidth]="true"></fa-icon>
|
||||||
|
</a>
|
||||||
|
<span *ngIf="!showPreviousBlocklink || !block" placement="bottom" class="disable nav-arrow prev">
|
||||||
<fa-icon [icon]="['fas', 'angle-right']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'angle-right']" [fixedWidth]="true"></fa-icon>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</ng-template>
|
|
||||||
<ng-template [ngIf]="blockHeight" i18n="shared.block-title">Block <ng-container *ngTemplateOutlet="blockTemplateContent"></ng-container></ng-template>
|
|
||||||
<ng-template #blockTemplateContent>
|
|
||||||
<span class="next-previous-blocks">
|
|
||||||
<a *ngIf="showNextBlocklink" [routerLink]="['/block/' | relativeUrl, nextBlockHeight]" (click)="navigateToNextBlock()" i18n-ngbTooltip="Next Block" ngbTooltip="Next Block" placement="bottom">
|
|
||||||
<fa-icon [icon]="['fas', 'angle-left']" [fixedWidth]="true"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<span *ngIf="!showNextBlocklink" placement="bottom" class="disable">
|
|
||||||
<fa-icon [icon]="['fas', 'angle-left']" [fixedWidth]="true"></fa-icon>
|
|
||||||
</span>
|
|
||||||
<a [routerLink]="['/block/' | relativeUrl, blockHash]">{{ blockHeight }}</a>
|
|
||||||
<a *ngIf="showPreviousBlocklink && block" [routerLink]="['/block/' | relativeUrl, block.previousblockhash]" (click)="navigateToPreviousBlock()" i18n-ngbTooltip="Previous Block" ngbTooltip="Previous Block" placement="bottom">
|
|
||||||
<fa-icon [icon]="['fas', 'angle-right']" [fixedWidth]="true"></fa-icon>
|
|
||||||
</a>
|
|
||||||
<span *ngIf="!showPreviousBlocklink" placement="bottom" class="disable">
|
|
||||||
<fa-icon [icon]="['fas', 'angle-right']" [fixedWidth]="true"></fa-icon>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</ng-template>
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
|
@ -111,7 +111,8 @@ h1 {
|
|||||||
|
|
||||||
.next-previous-blocks {
|
.next-previous-blocks {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
}
|
}
|
||||||
@ -125,6 +126,21 @@ h1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.time-ltr .next-previous-blocks {
|
||||||
|
.nav-arrow {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
.nav-arrow.next {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
.block-link {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
.nav-arrow.prev {
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.disable {
|
.disable {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: #393e5c73;
|
color: #393e5c73;
|
||||||
|
@ -57,6 +57,8 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
nextBlockSubscription: Subscription = undefined;
|
nextBlockSubscription: Subscription = undefined;
|
||||||
nextBlockSummarySubscription: Subscription = undefined;
|
nextBlockSummarySubscription: Subscription = undefined;
|
||||||
nextBlockTxListSubscription: Subscription = undefined;
|
nextBlockTxListSubscription: Subscription = undefined;
|
||||||
|
timeLtrSubscription: Subscription;
|
||||||
|
timeLtr: boolean;
|
||||||
|
|
||||||
@ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent;
|
@ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent;
|
||||||
|
|
||||||
@ -80,6 +82,10 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
this.network = this.stateService.network;
|
this.network = this.stateService.network;
|
||||||
this.itemsPerPage = this.stateService.env.ITEMS_PER_PAGE;
|
this.itemsPerPage = this.stateService.env.ITEMS_PER_PAGE;
|
||||||
|
|
||||||
|
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||||
|
this.timeLtr = !!ltr;
|
||||||
|
});
|
||||||
|
|
||||||
this.txsLoadingStatus$ = this.route.paramMap
|
this.txsLoadingStatus$ = this.route.paramMap
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(() => this.stateService.loadingIndicators$),
|
switchMap(() => this.stateService.loadingIndicators$),
|
||||||
@ -277,10 +283,12 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.keyNavigationSubscription = this.stateService.keyNavigation$.subscribe((event) => {
|
this.keyNavigationSubscription = this.stateService.keyNavigation$.subscribe((event) => {
|
||||||
if (this.showPreviousBlocklink && event.key === 'ArrowRight' && this.nextBlockHeight - 2 >= 0) {
|
const prevKey = this.timeLtr ? 'ArrowLeft' : 'ArrowRight';
|
||||||
|
const nextKey = this.timeLtr ? 'ArrowRight' : 'ArrowLeft';
|
||||||
|
if (this.showPreviousBlocklink && event.key === prevKey && this.nextBlockHeight - 2 >= 0) {
|
||||||
this.navigateToPreviousBlock();
|
this.navigateToPreviousBlock();
|
||||||
}
|
}
|
||||||
if (event.key === 'ArrowLeft') {
|
if (event.key === nextKey) {
|
||||||
if (this.showNextBlocklink) {
|
if (this.showNextBlocklink) {
|
||||||
this.navigateToNextBlock();
|
this.navigateToNextBlock();
|
||||||
} else {
|
} else {
|
||||||
@ -298,6 +306,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
this.blocksSubscription.unsubscribe();
|
this.blocksSubscription.unsubscribe();
|
||||||
this.networkChangedSubscription.unsubscribe();
|
this.networkChangedSubscription.unsubscribe();
|
||||||
this.queryParamsSubscription.unsubscribe();
|
this.queryParamsSubscription.unsubscribe();
|
||||||
|
this.timeLtrSubscription.unsubscribe();
|
||||||
this.unsubscribeNextBlockSubscriptions();
|
this.unsubscribeNextBlockSubscriptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,8 +401,8 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setNextAndPreviousBlockLink(){
|
setNextAndPreviousBlockLink(){
|
||||||
if (this.latestBlock && this.blockHeight) {
|
if (this.latestBlock) {
|
||||||
if (this.blockHeight === 0){
|
if (!this.blockHeight){
|
||||||
this.showPreviousBlocklink = false;
|
this.showPreviousBlocklink = false;
|
||||||
} else {
|
} else {
|
||||||
this.showPreviousBlocklink = true;
|
this.showPreviousBlocklink = true;
|
||||||
|
@ -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>
|
||||||
|
@ -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 {
|
||||||
@ -145,3 +145,9 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events : none;
|
pointer-events : none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.time-ltr {
|
||||||
|
.bitcoin-block {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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', network || '']">
|
||||||
<span>
|
<span>
|
||||||
|
<div class="blocks-wrapper">
|
||||||
<app-mempool-blocks></app-mempool-blocks>
|
<app-mempool-blocks></app-mempool-blocks>
|
||||||
<app-blockchain-blocks></app-blockchain-blocks>
|
<app-blockchain-blocks></app-blockchain-blocks>
|
||||||
<div id="divider"></div>
|
</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>
|
||||||
|
@ -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) {
|
||||||
|
.blockchain-wrapper {
|
||||||
.position-container {
|
.position-container {
|
||||||
left: 95%;
|
transform: translateX(95vw);
|
||||||
}
|
}
|
||||||
.position-container.liquid, .position-container.liquidtestnet {
|
.position-container.liquid, .position-container.liquidtestnet {
|
||||||
left: 50%;
|
transform: translateX(50vw);
|
||||||
}
|
}
|
||||||
.position-container.loading {
|
.position-container.loading {
|
||||||
left: 50%;
|
transform: translateX(50vw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.blockchain-wrapper.time-ltr {
|
||||||
|
.position-container {
|
||||||
|
transform: translateX(5vw);
|
||||||
|
}
|
||||||
|
.position-container.liquid, .position-container.liquidtestnet {
|
||||||
|
transform: translateX(50vw);
|
||||||
|
}
|
||||||
|
.position-container.loading {
|
||||||
|
transform: translateX(50vw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,3 +81,30 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blockchain-wrapper.ltr-transition .blocks-wrapper,
|
||||||
|
.blockchain-wrapper.ltr-transition .time-toggle {
|
||||||
|
transition: transform 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blockchain-wrapper.time-ltr .blocks-wrapper {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.blockchain-wrapper.time-ltr .time-toggle {
|
||||||
|
transform: translateX(-50%) scaleX(-1);
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[isLoading]="isLoading$ | async"
|
[isLoading]="isLoading$ | async"
|
||||||
[resolution]="75"
|
[resolution]="75"
|
||||||
[blockLimit]="stateService.blockVSize"
|
[blockLimit]="stateService.blockVSize"
|
||||||
[orientation]="'left'"
|
[orientation]="timeLtr ? 'right' : 'left'"
|
||||||
[flip]="true"
|
[flip]="true"
|
||||||
(txClickEvent)="onTxClick($event)"
|
(txClickEvent)="onTxClick($event)"
|
||||||
></app-block-overview-graph>
|
></app-block-overview-graph>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, ComponentRef, ViewChild, HostListener, Input, Output, EventEmitter,
|
import { Component, ComponentRef, ViewChild, HostListener, Input, Output, EventEmitter,
|
||||||
OnDestroy, OnChanges, ChangeDetectionStrategy, AfterViewInit } from '@angular/core';
|
OnInit, OnDestroy, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef, AfterViewInit } from '@angular/core';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { MempoolBlockDelta, TransactionStripped } from '../../interfaces/websocket.interface';
|
import { MempoolBlockDelta, TransactionStripped } from '../../interfaces/websocket.interface';
|
||||||
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
||||||
@ -14,7 +14,7 @@ import { Router } from '@angular/router';
|
|||||||
templateUrl: './mempool-block-overview.component.html',
|
templateUrl: './mempool-block-overview.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, AfterViewInit {
|
export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
|
||||||
@Input() index: number;
|
@Input() index: number;
|
||||||
@Output() txPreviewEvent = new EventEmitter<TransactionStripped | void>();
|
@Output() txPreviewEvent = new EventEmitter<TransactionStripped | void>();
|
||||||
|
|
||||||
@ -23,6 +23,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
|
|||||||
lastBlockHeight: number;
|
lastBlockHeight: number;
|
||||||
blockIndex: number;
|
blockIndex: number;
|
||||||
isLoading$ = new BehaviorSubject<boolean>(true);
|
isLoading$ = new BehaviorSubject<boolean>(true);
|
||||||
|
timeLtrSubscription: Subscription;
|
||||||
|
timeLtr: boolean;
|
||||||
|
chainDirection: string = 'right';
|
||||||
|
poolDirection: string = 'left';
|
||||||
|
|
||||||
blockSub: Subscription;
|
blockSub: Subscription;
|
||||||
deltaSub: Subscription;
|
deltaSub: Subscription;
|
||||||
@ -31,8 +35,18 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
|
|||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private cd: ChangeDetectorRef,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||||
|
this.timeLtr = !!ltr;
|
||||||
|
this.chainDirection = ltr ? 'left' : 'right';
|
||||||
|
this.poolDirection = ltr ? 'right' : 'left';
|
||||||
|
this.cd.markForCheck();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.blockSub = merge(
|
this.blockSub = merge(
|
||||||
of(true),
|
of(true),
|
||||||
@ -50,7 +64,7 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
|
|||||||
ngOnChanges(changes): void {
|
ngOnChanges(changes): void {
|
||||||
if (changes.index) {
|
if (changes.index) {
|
||||||
if (this.blockGraph) {
|
if (this.blockGraph) {
|
||||||
this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? 'right' : 'left');
|
this.blockGraph.clear(changes.index.currentValue > changes.index.previousValue ? this.chainDirection : this.poolDirection);
|
||||||
}
|
}
|
||||||
this.isLoading$.next(true);
|
this.isLoading$.next(true);
|
||||||
this.websocketService.startTrackMempoolBlock(changes.index.currentValue);
|
this.websocketService.startTrackMempoolBlock(changes.index.currentValue);
|
||||||
@ -60,16 +74,17 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
|
|||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.blockSub.unsubscribe();
|
this.blockSub.unsubscribe();
|
||||||
this.deltaSub.unsubscribe();
|
this.deltaSub.unsubscribe();
|
||||||
|
this.timeLtrSubscription.unsubscribe();
|
||||||
this.websocketService.stopTrackMempoolBlock();
|
this.websocketService.stopTrackMempoolBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceBlock(transactionsStripped: TransactionStripped[]): void {
|
replaceBlock(transactionsStripped: TransactionStripped[]): void {
|
||||||
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
|
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
|
||||||
if (this.blockIndex !== this.index) {
|
if (this.blockIndex !== this.index) {
|
||||||
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right';
|
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
|
||||||
this.blockGraph.enter(transactionsStripped, direction);
|
this.blockGraph.enter(transactionsStripped, direction);
|
||||||
} else {
|
} else {
|
||||||
this.blockGraph.replace(transactionsStripped, blockMined ? 'right' : 'left');
|
this.blockGraph.replace(transactionsStripped, blockMined ? this.chainDirection : this.poolDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
||||||
@ -81,10 +96,10 @@ export class MempoolBlockOverviewComponent implements OnDestroy, OnChanges, Afte
|
|||||||
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
|
const blockMined = (this.stateService.latestBlockHeight > this.lastBlockHeight);
|
||||||
|
|
||||||
if (this.blockIndex !== this.index) {
|
if (this.blockIndex !== this.index) {
|
||||||
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? 'left' : 'right';
|
const direction = (this.blockIndex == null || this.index < this.blockIndex) ? this.poolDirection : this.chainDirection;
|
||||||
this.blockGraph.replace(delta.added, direction);
|
this.blockGraph.replace(delta.added, direction);
|
||||||
} else {
|
} else {
|
||||||
this.blockGraph.update(delta.added, delta.removed, blockMined ? 'right' : 'left', blockMined);
|
this.blockGraph.update(delta.added, delta.removed, blockMined ? this.chainDirection : this.poolDirection, blockMined);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
this.lastBlockHeight = this.stateService.latestBlockHeight;
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,8 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
now = new Date().getTime();
|
now = new Date().getTime();
|
||||||
timeOffset = 0;
|
timeOffset = 0;
|
||||||
showMiningInfo = false;
|
showMiningInfo = false;
|
||||||
|
timeLtrSubscription: Subscription;
|
||||||
|
timeLtr: boolean;
|
||||||
|
|
||||||
blockWidth = 125;
|
blockWidth = 125;
|
||||||
blockPadding = 30;
|
blockPadding = 30;
|
||||||
@ -44,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;
|
||||||
@ -72,6 +74,11 @@ export class MempoolBlocksComponent 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';
|
||||||
}
|
}
|
||||||
@ -160,8 +167,10 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
if (this.markIndex === undefined) {
|
if (this.markIndex === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const prevKey = this.timeLtr ? 'ArrowLeft' : 'ArrowRight';
|
||||||
|
const nextKey = this.timeLtr ? 'ArrowRight' : 'ArrowLeft';
|
||||||
|
|
||||||
if (event.key === 'ArrowRight') {
|
if (event.key === prevKey) {
|
||||||
if (this.mempoolBlocks[this.markIndex - 1]) {
|
if (this.mempoolBlocks[this.markIndex - 1]) {
|
||||||
this.router.navigate([this.relativeUrlPipe.transform('mempool-block/'), this.markIndex - 1]);
|
this.router.navigate([this.relativeUrlPipe.transform('mempool-block/'), this.markIndex - 1]);
|
||||||
} else {
|
} else {
|
||||||
@ -173,7 +182,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (event.key === 'ArrowLeft') {
|
} else if (event.key === nextKey) {
|
||||||
if (this.mempoolBlocks[this.markIndex + 1]) {
|
if (this.mempoolBlocks[this.markIndex + 1]) {
|
||||||
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block/'), this.markIndex + 1]);
|
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block/'), this.markIndex + 1]);
|
||||||
}
|
}
|
||||||
@ -185,6 +194,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
this.markBlocksSubscription.unsubscribe();
|
this.markBlocksSubscription.unsubscribe();
|
||||||
this.blockSubscription.unsubscribe();
|
this.blockSubscription.unsubscribe();
|
||||||
this.networkSubscription.unsubscribe();
|
this.networkSubscription.unsubscribe();
|
||||||
|
this.timeLtrSubscription.unsubscribe();
|
||||||
clearTimeout(this.resetTransitionTimeout);
|
clearTimeout(this.resetTransitionTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,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;
|
||||||
|
@ -6,6 +6,7 @@ import { BlockExtended, DifficultyAdjustment, OptimizedMempoolStats } from '../i
|
|||||||
import { Router, NavigationStart } from '@angular/router';
|
import { Router, NavigationStart } from '@angular/router';
|
||||||
import { isPlatformBrowser } from '@angular/common';
|
import { isPlatformBrowser } from '@angular/common';
|
||||||
import { map, shareReplay } from 'rxjs/operators';
|
import { map, shareReplay } from 'rxjs/operators';
|
||||||
|
import { StorageService } from './storage.service';
|
||||||
|
|
||||||
interface MarkBlockState {
|
interface MarkBlockState {
|
||||||
blockHeight?: number;
|
blockHeight?: number;
|
||||||
@ -108,10 +109,12 @@ export class StateService {
|
|||||||
keyNavigation$ = new Subject<KeyboardEvent>();
|
keyNavigation$ = new Subject<KeyboardEvent>();
|
||||||
|
|
||||||
blockScrolling$: Subject<boolean> = new Subject<boolean>();
|
blockScrolling$: Subject<boolean> = new Subject<boolean>();
|
||||||
|
timeLtr: BehaviorSubject<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(PLATFORM_ID) private platformId: any,
|
@Inject(PLATFORM_ID) private platformId: any,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private storageService: StorageService,
|
||||||
) {
|
) {
|
||||||
const browserWindow = window || {};
|
const browserWindow = window || {};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -147,6 +150,11 @@ export class StateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.blockVSize = this.env.BLOCK_WEIGHT_UNITS / 4;
|
this.blockVSize = this.env.BLOCK_WEIGHT_UNITS / 4;
|
||||||
|
|
||||||
|
this.timeLtr = new BehaviorSubject<boolean>(this.storageService.getValue('time-preference-ltr') === 'true');
|
||||||
|
this.timeLtr.subscribe((ltr) => {
|
||||||
|
this.storageService.setValue('time-preference-ltr', ltr ? 'true' : 'false');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setNetworkBasedonUrl(url: string) {
|
setNetworkBasedonUrl(url: string) {
|
||||||
|
@ -4,7 +4,7 @@ import { NgbCollapse, NgbCollapseModule, NgbRadioGroup, NgbTypeaheadModule } fro
|
|||||||
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
||||||
import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle,
|
import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle,
|
||||||
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown,
|
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown,
|
||||||
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft } from '@fortawesome/free-solid-svg-icons';
|
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||||
import { MasterPageComponent } from '../components/master-page/master-page.component';
|
import { MasterPageComponent } from '../components/master-page/master-page.component';
|
||||||
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
|
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
|
||||||
@ -291,6 +291,7 @@ export class SharedModule {
|
|||||||
library.addIcons(faFileAlt);
|
library.addIcons(faFileAlt);
|
||||||
library.addIcons(faRedoAlt);
|
library.addIcons(faRedoAlt);
|
||||||
library.addIcons(faArrowAltCircleRight);
|
library.addIcons(faArrowAltCircleRight);
|
||||||
|
library.addIcons(faArrowsRotate);
|
||||||
library.addIcons(faExternalLinkAlt);
|
library.addIcons(faExternalLinkAlt);
|
||||||
library.addIcons(faSortUp);
|
library.addIcons(faSortUp);
|
||||||
library.addIcons(faCaretUp);
|
library.addIcons(faCaretUp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user