diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 0c4a1cbb7..2c3f1ad8c 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,9 +1,9 @@
-
+
- + diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 63ca22626..135a8b842 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -26,43 +26,14 @@ position: absolute; left: 0; top: 75px; - transform: translateX(50vw); + --divider-offset: 50vw; + --mempool-offset: 0px; + transform: translateX(calc(var(--divider-offset) + var(--mempool-offset))); } -.position-container.liquid, .position-container.liquidtestnet { - 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) { - .blockchain-wrapper { - .position-container { - transform: translateX(95vw); - } - .position-container.liquid, .position-container.liquidtestnet { - transform: translateX(50vw); - } - .position-container.loading { - 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); - } +.blockchain-wrapper.time-ltr { + .position-container { + transform: translateX(calc(100vw - var(--divider-offset) - var(--mempool-offset))); } } diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index ab9875a4c..5eb2ed481 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, HostListener, ChangeDetectorRef } from '@angular/core'; import { firstValueFrom, Subscription } from 'rxjs'; import { StateService } from '../../services/state.service'; @@ -13,43 +13,95 @@ export class BlockchainComponent implements OnInit, OnDestroy { @Input() pageIndex: number; @Input() blocksPerPage: number = 8; @Input() minScrollWidth: number = 0; + @Input() scrollableMempool: boolean = false; + + @Output() mempoolOffsetChange: EventEmitter = new EventEmitter(); network: string; timeLtrSubscription: Subscription; timeLtr: boolean = this.stateService.timeLtr.value; ltrTransitionEnabled = false; + flipping = false; connectionStateSubscription: Subscription; loadingTip: boolean = true; connected: boolean = true; + dividerOffset: number = 0; + mempoolOffset: number = 0; + constructor( public stateService: StateService, + private cd: ChangeDetectorRef, ) {} - ngOnInit() { + ngOnInit(): void { + this.onResize(); this.network = this.stateService.network; this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { this.timeLtr = !!ltr; }); this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => { this.connected = (state === 2); - }) - firstValueFrom(this.stateService.chainTip$).then(tip => { + }); + firstValueFrom(this.stateService.chainTip$).then(() => { this.loadingTip = false; }); } - ngOnDestroy() { + ngOnDestroy(): void { this.timeLtrSubscription.unsubscribe(); this.connectionStateSubscription.unsubscribe(); } - trackByPageFn(index: number, item: { index: number }) { + trackByPageFn(index: number, item: { index: number }): number { return item.index; } - toggleTimeDirection() { - this.ltrTransitionEnabled = true; - this.stateService.timeLtr.next(!this.timeLtr); + toggleTimeDirection(): void { + this.ltrTransitionEnabled = false; + const prevOffset = this.mempoolOffset; + this.mempoolOffset = 0; + this.mempoolOffsetChange.emit(0); + setTimeout(() => { + this.ltrTransitionEnabled = true; + this.flipping = true; + this.stateService.timeLtr.next(!this.timeLtr); + setTimeout(() => { + this.ltrTransitionEnabled = false; + this.flipping = false; + this.mempoolOffset = prevOffset; + this.mempoolOffsetChange.emit(this.mempoolOffset); + }, 1000); + }, 0); + this.cd.markForCheck(); + } + + onMempoolWidthChange(width): void { + if (this.flipping) { + return; + } + this.mempoolOffset = Math.max(0, width - this.dividerOffset); + this.cd.markForCheck(); + setTimeout(() => { + this.mempoolOffsetChange.emit(this.mempoolOffset); + }, 0); + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + if (window.innerWidth >= 768) { + if (this.stateService.isLiquid()) { + this.dividerOffset = 420; + } else { + this.dividerOffset = window.innerWidth * 0.5; + } + } else { + if (this.stateService.isLiquid()) { + this.dividerOffset = window.innerWidth * 0.5; + } else { + this.dividerOffset = window.innerWidth * 0.95; + } + } + this.cd.markForCheck(); } } 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 561f01585..3e7ba310a 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 } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core'; import { Subscription, Observable, fromEvent, merge, of, combineLatest } from 'rxjs'; import { MempoolBlock } from '../../interfaces/websocket.interface'; import { StateService } from '../../services/state.service'; import { Router } from '@angular/router'; -import { take, map, switchMap } from 'rxjs/operators'; +import { take, map, switchMap, tap } from 'rxjs/operators'; import { feeLevels, mempoolFeeColors } from '../../app.constants'; import { specialBlocks } from '../../app.constants'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; @@ -29,6 +29,9 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() count: number = null; @Input() spotlight: number = 0; @Input() getHref?: (index) => string = (index) => `/mempool-block/${index}`; + @Input() allBlocks: boolean = false; + + @Output() widthChange: EventEmitter = new EventEmitter(); specialBlocks = specialBlocks; mempoolBlocks: MempoolBlock[] = []; @@ -145,7 +148,12 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { this.updateMempoolBlockStyles(); this.calculateTransactionPosition(); + return this.mempoolBlocks; + }), + tap(() => { + this.cd.markForCheck(); + this.widthChange.emit(this.containerOffset + this.mempoolBlocks.length * this.blockOffset); }) ); @@ -254,7 +262,10 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { reduceEmptyBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; - const blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); + let blocksAmount = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; + if (!this.allBlocks) { + blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); + } while (blocks.length < blocksAmount) { blocks.push({ blockSize: 0, @@ -274,10 +285,10 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; - let blocksAmount; + let blocksAmount = this.stateService.env.MEMPOOL_BLOCKS_AMOUNT; if (this.count) { blocksAmount = 8; - } else { + } else if (!this.allBlocks) { blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); } while (blocks.length > blocksAmount) { diff --git a/frontend/src/app/components/start/start.component.html b/frontend/src/app/components/start/start.component.html index ec4bf4805..5cf7b4fd9 100644 --- a/frontend/src/app/components/start/start.component.html +++ b/frontend/src/app/components/start/start.component.html @@ -18,7 +18,7 @@ (dragstart)="onDragStart($event)" (scroll)="onScroll($event)" > - +
diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index 3bd0c086e..1793818a9 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -44,6 +44,7 @@ export class StartComponent implements OnInit, OnDestroy { lastUpdate: number = 0; lastMouseX: number; velocity: number = 0; + mempoolOffset: number = 0; constructor( private stateService: StateService, @@ -117,6 +118,12 @@ export class StartComponent implements OnInit, OnDestroy { }); } + onMempoolOffsetChange(offset): void { + const delta = offset - this.mempoolOffset; + this.addConvertedScrollOffset(delta); + this.mempoolOffset = offset; + } + @HostListener('window:resize', ['$event']) onResize(): void { this.isMobile = window.innerWidth <= 767.98; @@ -350,7 +357,7 @@ export class StartComponent implements OnInit, OnDestroy { resetScroll(): void { this.scrollToBlock(this.chainTip); - this.blockchainContainer.nativeElement.scrollLeft = 0; + this.setScrollLeft(0); } getPageIndexOf(height: number): number { @@ -368,9 +375,17 @@ export class StartComponent implements OnInit, OnDestroy { getConvertedScrollOffset(): number { if (this.timeLtr) { - return -this.blockchainContainer?.nativeElement?.scrollLeft || 0; + return -(this.blockchainContainer?.nativeElement?.scrollLeft || 0) - this.mempoolOffset; } else { - return this.blockchainContainer?.nativeElement?.scrollLeft || 0; + return (this.blockchainContainer?.nativeElement?.scrollLeft || 0) - this.mempoolOffset; + } + } + + setScrollLeft(offset: number): void { + if (this.timeLtr) { + this.blockchainContainer.nativeElement.scrollLeft = offset - this.mempoolOffset; + } else { + this.blockchainContainer.nativeElement.scrollLeft = offset + this.mempoolOffset; } } @@ -388,7 +403,7 @@ export class StartComponent implements OnInit, OnDestroy { ngOnDestroy() { if (this.blockchainContainer?.nativeElement) { // clean up scroll position to prevent caching wrong scroll in Firefox - this.blockchainContainer.nativeElement.scrollLeft = 0; + this.setScrollLeft(0); } this.timeLtrSubscription.unsubscribe(); this.chainTipSubscription.unsubscribe();