Merge pull request #4064 from mempool/mononaut/better-mobile-difficulty-tooltip

Improve difficulty tooltip display on mobile
This commit is contained in:
softsimon 2023-08-04 18:41:07 +09:00 committed by GitHub
commit 9da9c2750d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 32 deletions

View File

@ -4,38 +4,56 @@
class="difficulty-tooltip" class="difficulty-tooltip"
[style.visibility]="status ? 'visible' : 'hidden'" [style.visibility]="status ? 'visible' : 'hidden'"
[style.left]="tooltipPosition.x + 'px'" [style.left]="tooltipPosition.x + 'px'"
[style.top]="tooltipPosition.y + 'px'" [style.top]="tooltipPosition.y + (isMobile ? -60 : 0) + 'px'"
> >
<ng-container [ngSwitch]="status"> <ng-container *ngIf="!isMobile" [ngSwitch]="status">
<ng-container *ngSwitchCase="'mined'"> <ng-container *ngSwitchCase="'mined'">
<ng-container *ngIf="isAhead"> <ng-container *ngIf="isAhead">
<ng-container *ngTemplateOutlet="expected === 1 ? blocksSingular : blocksPlural; context: {$implicit: expected }"></ng-container> <ng-container *ngTemplateOutlet="expected === 1 ? expectedMinedBlocksSingular : expectedMinedBlocksPlural; context: {$implicit: expected }"></ng-container>
<ng-template #blocksPlural let-i i18n="difficulty-box.expected-blocks">{{ i }} blocks expected</ng-template>
<ng-template #blocksSingular let-i i18n="difficulty-box.expected-block">{{ i }} block expected</ng-template>
</ng-container> </ng-container>
<ng-container *ngIf="!isAhead"> <ng-container *ngIf="!isAhead">
<ng-container *ngTemplateOutlet="mined === 1 ? blocksSingular : blocksPlural; context: {$implicit: mined }"></ng-container> <ng-container *ngTemplateOutlet="mined === 1 ? minedBlocksSingular : minedBlocksPlural; context: {$implicit: mined }"></ng-container>
<ng-template #blocksPlural let-i i18n="difficulty-box.mined-blocks">{{ i }} blocks mined</ng-template>
<ng-template #blocksSingular let-i i18n="difficulty-box.mined-block">{{ i }} block mined</ng-template>
</ng-container> </ng-container>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'remaining'"> <ng-container *ngSwitchCase="'remaining'">
<ng-container *ngTemplateOutlet="remaining === 1 ? blocksSingular : blocksPlural; context: {$implicit: remaining }"></ng-container> <ng-container *ngTemplateOutlet="remaining === 1 ? remainingBlocksSingular : remainingBlocksPlural; context: {$implicit: remaining }"></ng-container>
<ng-template #blocksPlural let-i i18n="difficulty-box.remaining-blocks">{{ i }} blocks remaining</ng-template>
<ng-template #blocksSingular let-i i18n="difficulty-box.remaining-block">{{ i }} block remaining</ng-template>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'ahead'"> <ng-container *ngSwitchCase="'ahead'">
<ng-container *ngTemplateOutlet="ahead === 1 ? blocksSingular : blocksPlural; context: {$implicit: ahead }"></ng-container> <ng-container *ngTemplateOutlet="ahead === 1 ? aheadBlocksSingular : aheadBlocksPlural; context: {$implicit: ahead }"></ng-container>
<ng-template #blocksPlural let-i i18n="difficulty-box.blocks-ahead">{{ i }} blocks ahead</ng-template>
<ng-template #blocksSingular let-i i18n="difficulty-box.block-ahead">{{ i }} block ahead</ng-template>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'behind'"> <ng-container *ngSwitchCase="'behind'">
<ng-container *ngTemplateOutlet="behind === 1 ? blocksSingular : blocksPlural; context: {$implicit: behind }"></ng-container> <ng-container *ngTemplateOutlet="behind === 1 ? behindBlocksSingular : behindBlocksPlural; context: {$implicit: behind }"></ng-container>
<ng-template #blocksPlural let-i i18n="difficulty-box.blocks-behind">{{ i }} blocks behind</ng-template>
<ng-template #blocksSingular let-i i18n="difficulty-box.block-behind">{{ i }} block behind</ng-template>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="'next'"> <ng-container *ngSwitchCase="'next'">
<span class="next-block" i18n="@@bdf0e930eb22431140a2eaeacd809cc5f8ebd38c">Next Block</span> <span class="next-block" i18n="@@bdf0e930eb22431140a2eaeacd809cc5f8ebd38c">Next Block</span>
</ng-container> </ng-container>
</ng-container> </ng-container>
</div> <ng-container *ngIf="isMobile">
<ng-container *ngIf="isAhead">
<ng-container *ngTemplateOutlet="expected === 1 ? minedBlocksSingular : minedBlocksPlural; context: {$implicit: expected }"></ng-container>
</ng-container>
<ng-container *ngIf="!isAhead">
<ng-container *ngTemplateOutlet="mined === 1 ? minedBlocksSingular : minedBlocksPlural; context: {$implicit: mined }"></ng-container>
</ng-container>
<br>
<ng-container *ngTemplateOutlet="remaining === 1 ? remainingBlocksSingular : remainingBlocksPlural; context: {$implicit: remaining }"></ng-container>
<br>
<ng-container *ngIf="ahead > 0">
<ng-container *ngTemplateOutlet="ahead === 1 ? aheadBlocksSingular : aheadBlocksPlural; context: {$implicit: ahead }"></ng-container>
</ng-container>
<ng-container *ngIf="behind > 0">
<ng-container *ngTemplateOutlet="behind === 1 ? behindBlocksSingular : behindBlocksPlural; context: {$implicit: behind }"></ng-container>
</ng-container>
</ng-container>
</div>
<ng-template #expectedMinedBlocksPlural let-i i18n="difficulty-box.expected-blocks">{{ i }} blocks expected</ng-template>
<ng-template #expectedMinedBlocksSingular let-i i18n="difficulty-box.expected-block">{{ i }} block expected</ng-template>
<ng-template #minedBlocksPlural let-i i18n="difficulty-box.mined-blocks">{{ i }} blocks mined</ng-template>
<ng-template #minedBlocksSingular let-i i18n="difficulty-box.mined-block">{{ i }} block mined</ng-template>
<ng-template #remainingBlocksPlural let-i i18n="difficulty-box.remaining-blocks">{{ i }} blocks remaining</ng-template>
<ng-template #remainingBlocksSingular let-i i18n="difficulty-box.remaining-block">{{ i }} block remaining</ng-template>
<ng-template #aheadBlocksPlural let-i i18n="difficulty-box.blocks-ahead">{{ i }} blocks ahead</ng-template>
<ng-template #aheadBlocksSingular let-i i18n="difficulty-box.block-ahead">{{ i }} block ahead</ng-template>
<ng-template #behindBlocksPlural let-i i18n="difficulty-box.blocks-behind">{{ i }} blocks behind</ng-template>
<ng-template #behindBlocksSingular let-i i18n="difficulty-box.block-behind">{{ i }} block behind</ng-template>

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, ViewChild, Input, OnChanges } from '@angular/core'; import { Component, ElementRef, ViewChild, Input, OnChanges, HostListener } from '@angular/core';
interface EpochProgress { interface EpochProgress {
base: string; base: string;
@ -35,12 +35,15 @@ export class DifficultyTooltipComponent implements OnChanges {
remaining: number; remaining: number;
isAhead: boolean; isAhead: boolean;
isBehind: boolean; isBehind: boolean;
isMobile: boolean;
tooltipPosition = { x: 0, y: 0 }; tooltipPosition = { x: 0, y: 0 };
@ViewChild('tooltip') tooltipElement: ElementRef<HTMLCanvasElement>; @ViewChild('tooltip') tooltipElement: ElementRef<HTMLCanvasElement>;
constructor() {} constructor() {
this.onResize();
}
ngOnChanges(changes): void { ngOnChanges(changes): void {
if (changes.cursorPosition && changes.cursorPosition.currentValue) { if (changes.cursorPosition && changes.cursorPosition.currentValue) {
@ -63,4 +66,9 @@ export class DifficultyTooltipComponent implements OnChanges {
this.isBehind = this.behind > 0; this.isBehind = this.behind > 0;
} }
} }
@HostListener('window:resize', ['$event'])
onResize(): void {
this.isMobile = window.innerWidth <= 767.98;
}
} }

View File

@ -4,7 +4,7 @@
<div class="card-body more-padding"> <div class="card-body more-padding">
<div class="difficulty-adjustment-container" *ngIf="(isLoadingWebSocket$ | async) === false && (difficultyEpoch$ | async) as epochData; else loadingDifficulty"> <div class="difficulty-adjustment-container" *ngIf="(isLoadingWebSocket$ | async) === false && (difficultyEpoch$ | async) as epochData; else loadingDifficulty">
<div class="epoch-progress"> <div class="epoch-progress">
<svg class="epoch-blocks" height="22px" width="100%" viewBox="0 0 224 9" shape-rendering="crispEdges" preserveAspectRatio="none"> <svg #epochSvg class="epoch-blocks" height="22px" width="100%" viewBox="0 0 224 9" shape-rendering="crispEdges" preserveAspectRatio="none">
<defs> <defs>
<linearGradient id="diff-gradient" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse"> <linearGradient id="diff-gradient" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#105fb0" /> <stop offset="0%" stop-color="#105fb0" />
@ -22,7 +22,7 @@
class="rect {{rect.status}}" class="rect {{rect.status}}"
[class.hover]="hoverSection && rect.status === hoverSection.status" [class.hover]="hoverSection && rect.status === hoverSection.status"
(pointerover)="onHover($event, rect);" (pointerover)="onHover($event, rect);"
(pointerout)="onBlur($event);" (pointerout)="onBlur();"
> >
<animate <animate
*ngIf="rect.status === 'next'" *ngIf="rect.status === 'next'"

View File

@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, ElementRef, ViewChild, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
import { combineLatest, Observable, timer } from 'rxjs'; import { combineLatest, Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { StateService } from '../..//services/state.service'; import { StateService } from '../..//services/state.service';
interface EpochProgress { interface EpochProgress {
@ -44,6 +44,8 @@ export class DifficultyComponent implements OnInit {
@Input() showProgress = true; @Input() showProgress = true;
@Input() showHalving = false; @Input() showHalving = false;
@Input() showTitle = true; @Input() showTitle = true;
@ViewChild('epochSvg') epochSvgElement: ElementRef<SVGElement>;
isLoadingWebSocket$: Observable<boolean>; isLoadingWebSocket$: Observable<boolean>;
difficultyEpoch$: Observable<EpochProgress>; difficultyEpoch$: Observable<EpochProgress>;
@ -191,21 +193,26 @@ export class DifficultyComponent implements OnInit {
} }
@HostListener('pointerdown', ['$event']) @HostListener('pointerdown', ['$event'])
onPointerDown(event) { onPointerDown(event): void {
this.onPointerMove(event); if (this.epochSvgElement.nativeElement?.contains(event.target)) {
this.onPointerMove(event);
event.preventDefault();
}
} }
@HostListener('pointermove', ['$event']) @HostListener('pointermove', ['$event'])
onPointerMove(event) { onPointerMove(event): void {
this.tooltipPosition = { x: event.clientX, y: event.clientY }; if (this.epochSvgElement.nativeElement?.contains(event.target)) {
this.cd.markForCheck(); this.tooltipPosition = { x: event.clientX, y: event.clientY };
this.cd.markForCheck();
}
} }
onHover(event, rect): void { onHover(_, rect): void {
this.hoverSection = rect; this.hoverSection = rect;
} }
onBlur(event): void { onBlur(): void {
this.hoverSection = null; this.hoverSection = null;
} }
} }