Merge pull request #4202 from mempool/mononaut/dynamic-width-chain
Dynamic width chain
This commit is contained in:
commit
3aa938a94b
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, HostListener, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, HostListener, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { firstValueFrom, Subscription } from 'rxjs';
|
import { firstValueFrom, Subscription } from 'rxjs';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
|
|
||||||
@ -8,12 +8,13 @@ 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, OnDestroy {
|
export class BlockchainComponent implements OnInit, OnDestroy, OnChanges {
|
||||||
@Input() pages: any[] = [];
|
@Input() pages: any[] = [];
|
||||||
@Input() pageIndex: number;
|
@Input() pageIndex: number;
|
||||||
@Input() blocksPerPage: number = 8;
|
@Input() blocksPerPage: number = 8;
|
||||||
@Input() minScrollWidth: number = 0;
|
@Input() minScrollWidth: number = 0;
|
||||||
@Input() scrollableMempool: boolean = false;
|
@Input() scrollableMempool: boolean = false;
|
||||||
|
@Input() containerWidth: number;
|
||||||
|
|
||||||
@Output() mempoolOffsetChange: EventEmitter<number> = new EventEmitter();
|
@Output() mempoolOffsetChange: EventEmitter<number> = new EventEmitter();
|
||||||
|
|
||||||
@ -85,19 +86,25 @@ export class BlockchainComponent implements OnInit, OnDestroy {
|
|||||||
this.mempoolOffsetChange.emit(this.mempoolOffset);
|
this.mempoolOffsetChange.emit(this.mempoolOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if (changes.containerWidth) {
|
||||||
|
this.onResize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onResize(): void {
|
onResize(): void {
|
||||||
if (window.innerWidth >= 768) {
|
const width = this.containerWidth || window.innerWidth;
|
||||||
|
if (width >= 768) {
|
||||||
if (this.stateService.isLiquid()) {
|
if (this.stateService.isLiquid()) {
|
||||||
this.dividerOffset = 420;
|
this.dividerOffset = 420;
|
||||||
} else {
|
} else {
|
||||||
this.dividerOffset = window.innerWidth * 0.5;
|
this.dividerOffset = width * 0.5;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.stateService.isLiquid()) {
|
if (this.stateService.isLiquid()) {
|
||||||
this.dividerOffset = window.innerWidth * 0.5;
|
this.dividerOffset = width * 0.5;
|
||||||
} else {
|
} else {
|
||||||
this.dividerOffset = window.innerWidth * 0.95;
|
this.dividerOffset = width * 0.95;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
|
@ -89,7 +89,7 @@ export class MasterPageComponent implements OnInit {
|
|||||||
|
|
||||||
hamburgerClick(event): void {
|
hamburgerClick(event): void {
|
||||||
if (this.menuComponent) {
|
if (this.menuComponent) {
|
||||||
this.menuComponent.hambugerClick();
|
this.menuComponent.hamburgerClick();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 65px;
|
top: 65px;
|
||||||
transition: 0.25s;
|
transition: 0.25s;
|
||||||
margin-left: -250px;
|
margin-left: -225px;
|
||||||
box-shadow: 5px 0px 30px 0px #000;
|
box-shadow: 5px 0px 30px 0px #000;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,9 @@ export class MenuComponent implements OnInit {
|
|||||||
this.router.navigateByUrl(link);
|
this.router.navigateByUrl(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
hambugerClick() {
|
hamburgerClick() {
|
||||||
this.navOpen = !this.navOpen;
|
this.navOpen = !this.navOpen;
|
||||||
|
this.stateService.menuOpen$.next(this.navOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:click', ['$event'])
|
@HostListener('window:click', ['$event'])
|
||||||
|
@ -10,15 +10,25 @@
|
|||||||
|
|
||||||
<div *ngIf="countdown > 0" class="warning-label">{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!</div>
|
<div *ngIf="countdown > 0" class="warning-label">{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!</div>
|
||||||
|
|
||||||
<div class="blockchain-wrapper" [class.time-ltr]="timeLtr" [class.time-rtl]="!timeLtr">
|
<div class="blockchain-wrapper" [class.time-ltr]="timeLtr" [class.time-rtl]="!timeLtr" #blockchainWrapper>
|
||||||
<div id="blockchain-container" [dir]="timeLtr ? 'rtl' : 'ltr'" #blockchainContainer
|
<div id="blockchain-container" [dir]="timeLtr ? 'rtl' : 'ltr'" #blockchainContainer
|
||||||
|
[class.menu-open]="menuOpen"
|
||||||
|
[class.menu-closing]="menuSliding && !menuOpen"
|
||||||
(mousedown)="onMouseDown($event)"
|
(mousedown)="onMouseDown($event)"
|
||||||
(pointerdown)="onPointerDown($event)"
|
(pointerdown)="onPointerDown($event)"
|
||||||
(touchmove)="onTouchMove($event)"
|
(touchmove)="onTouchMove($event)"
|
||||||
(dragstart)="onDragStart($event)"
|
(dragstart)="onDragStart($event)"
|
||||||
(scroll)="onScroll($event)"
|
(scroll)="onScroll($event)"
|
||||||
>
|
>
|
||||||
<app-blockchain [pageIndex]="pageIndex" [pages]="pages" [blocksPerPage]="blocksPerPage" [minScrollWidth]="minScrollWidth" [scrollableMempool]="true" (mempoolOffsetChange)="onMempoolOffsetChange($event)"></app-blockchain>
|
<app-blockchain
|
||||||
|
[containerWidth]="chainWidth"
|
||||||
|
[pageIndex]="pageIndex"
|
||||||
|
[pages]="pages"
|
||||||
|
[blocksPerPage]="blocksPerPage"
|
||||||
|
[minScrollWidth]="minScrollWidth"
|
||||||
|
[scrollableMempool]="true"
|
||||||
|
(mempoolOffsetChange)="onMempoolOffsetChange($event)"
|
||||||
|
></app-blockchain>
|
||||||
</div>
|
</div>
|
||||||
<div class="reset-scroll" [class.hidden]="pageIndex === 0" (click)="resetScroll()">
|
<div class="reset-scroll" [class.hidden]="pageIndex === 0" (click)="resetScroll()">
|
||||||
<fa-icon [icon]="['fas', 'circle-left']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'circle-left']" [fixedWidth]="true"></fa-icon>
|
||||||
|
@ -6,6 +6,20 @@
|
|||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
|
width: calc(100% + 120px);
|
||||||
|
|
||||||
|
transform: translateX(0px);
|
||||||
|
transition: transform 0;
|
||||||
|
|
||||||
|
&.menu-open {
|
||||||
|
transform: translateX(-112.5px);
|
||||||
|
transition: transform 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.menu-closing {
|
||||||
|
transform: translateX(0px);
|
||||||
|
transition: transform 0.25s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#blockchain-container::-webkit-scrollbar {
|
#blockchain-container::-webkit-scrollbar {
|
||||||
|
@ -28,8 +28,10 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
lastMark: MarkBlockState;
|
lastMark: MarkBlockState;
|
||||||
markBlockSubscription: Subscription;
|
markBlockSubscription: Subscription;
|
||||||
blockCounterSubscription: Subscription;
|
blockCounterSubscription: Subscription;
|
||||||
|
@ViewChild('blockchainWrapper', { static: true }) blockchainWrapper: ElementRef;
|
||||||
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
||||||
resetScrollSubscription: Subscription;
|
resetScrollSubscription: Subscription;
|
||||||
|
menuSubscription: Subscription;
|
||||||
|
|
||||||
isMobile: boolean = false;
|
isMobile: boolean = false;
|
||||||
isiOS: boolean = false;
|
isiOS: boolean = false;
|
||||||
@ -49,6 +51,12 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
velocity: number = 0;
|
velocity: number = 0;
|
||||||
mempoolOffset: number = 0;
|
mempoolOffset: number = 0;
|
||||||
|
|
||||||
|
private resizeObserver: ResizeObserver;
|
||||||
|
chainWidth: number = window.innerWidth;
|
||||||
|
menuOpen: boolean = false;
|
||||||
|
menuSliding: boolean = false;
|
||||||
|
menuTimeout: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
) {
|
) {
|
||||||
@ -151,6 +159,13 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
this.stateService.resetScroll$.next(false);
|
this.stateService.resetScroll$.next(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.menuSubscription = this.stateService.menuOpen$.subscribe((open) => {
|
||||||
|
if (this.menuOpen !== open) {
|
||||||
|
this.menuOpen = open;
|
||||||
|
this.applyMenuScroll(this.menuOpen);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMempoolOffsetChange(offset): void {
|
onMempoolOffsetChange(offset): void {
|
||||||
@ -171,9 +186,18 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyMenuScroll(opening: boolean): void {
|
||||||
|
this.menuSliding = true;
|
||||||
|
window.clearTimeout(this.menuTimeout);
|
||||||
|
this.menuTimeout = window.setTimeout(() => {
|
||||||
|
this.menuSliding = false;
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(): void {
|
onResize(): void {
|
||||||
this.isMobile = window.innerWidth <= 767.98;
|
this.chainWidth = window.innerWidth;
|
||||||
|
this.isMobile = this.chainWidth <= 767.98;
|
||||||
let firstVisibleBlock;
|
let firstVisibleBlock;
|
||||||
let offset;
|
let offset;
|
||||||
if (this.blockchainContainer?.nativeElement != null) {
|
if (this.blockchainContainer?.nativeElement != null) {
|
||||||
@ -188,7 +212,7 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.blocksPerPage = Math.ceil(window.innerWidth / this.blockWidth);
|
this.blocksPerPage = Math.ceil(this.chainWidth / this.blockWidth);
|
||||||
this.pageWidth = this.blocksPerPage * this.blockWidth;
|
this.pageWidth = this.blocksPerPage * this.blockWidth;
|
||||||
this.minScrollWidth = this.firstPageWidth + (this.pageWidth * 2);
|
this.minScrollWidth = this.firstPageWidth + (this.pageWidth * 2);
|
||||||
|
|
||||||
@ -295,7 +319,7 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
onScroll(e) {
|
onScroll(e) {
|
||||||
const middlePage = this.pageIndex === 0 ? this.pages[0] : this.pages[1];
|
const middlePage = this.pageIndex === 0 ? this.pages[0] : this.pages[1];
|
||||||
// compensate for css transform
|
// compensate for css transform
|
||||||
const translation = (this.isMobile ? window.innerWidth * 0.95 : window.innerWidth * 0.5);
|
const translation = (this.isMobile ? this.chainWidth * 0.95 : this.chainWidth * 0.5);
|
||||||
const backThreshold = middlePage.offset + (this.pageWidth * 0.5) + translation;
|
const backThreshold = middlePage.offset + (this.pageWidth * 0.5) + translation;
|
||||||
const forwardThreshold = middlePage.offset - (this.pageWidth * 0.5) + translation;
|
const forwardThreshold = middlePage.offset - (this.pageWidth * 0.5) + translation;
|
||||||
const scrollLeft = this.getConvertedScrollOffset();
|
const scrollLeft = this.getConvertedScrollOffset();
|
||||||
@ -414,10 +438,10 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
|
|
||||||
blockInViewport(height: number): boolean {
|
blockInViewport(height: number): boolean {
|
||||||
const firstHeight = this.pages[0].height;
|
const firstHeight = this.pages[0].height;
|
||||||
const translation = (this.isMobile ? window.innerWidth * 0.95 : window.innerWidth * 0.5);
|
const translation = (this.isMobile ? this.chainWidth * 0.95 : this.chainWidth * 0.5);
|
||||||
const firstX = this.pages[0].offset - this.getConvertedScrollOffset() + translation;
|
const firstX = this.pages[0].offset - this.getConvertedScrollOffset() + translation;
|
||||||
const xPos = firstX + ((firstHeight - height) * 155);
|
const xPos = firstX + ((firstHeight - height) * 155);
|
||||||
return xPos > -55 && xPos < (window.innerWidth - 100);
|
return xPos > -55 && xPos < (this.chainWidth - 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
getConvertedScrollOffset(): number {
|
getConvertedScrollOffset(): number {
|
||||||
@ -458,5 +482,6 @@ export class StartComponent implements OnInit, OnDestroy, DoCheck {
|
|||||||
this.markBlockSubscription.unsubscribe();
|
this.markBlockSubscription.unsubscribe();
|
||||||
this.blockCounterSubscription.unsubscribe();
|
this.blockCounterSubscription.unsubscribe();
|
||||||
this.resetScrollSubscription.unsubscribe();
|
this.resetScrollSubscription.unsubscribe();
|
||||||
|
this.menuSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,7 @@ export class StateService {
|
|||||||
rateUnits$: BehaviorSubject<string>;
|
rateUnits$: BehaviorSubject<string>;
|
||||||
|
|
||||||
searchFocus$: Subject<boolean> = new Subject<boolean>();
|
searchFocus$: Subject<boolean> = new Subject<boolean>();
|
||||||
|
menuOpen$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(PLATFORM_ID) private platformId: any,
|
@Inject(PLATFORM_ID) private platformId: any,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user