From b8cfeb579b7c9c2e41cd651d8a3a5bc6a4cdbc5b Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 11 Aug 2024 20:38:54 +0000 Subject: [PATCH 1/2] make accelerations magical again --- .../acceleration-sparkles.component.html | 5 ++ .../acceleration-sparkles.component.scss | 45 ++++++++++++ .../acceleration-sparkles.component.ts | 71 +++++++++++++++++++ .../mempool-blocks.component.html | 3 +- .../mempool-blocks.component.ts | 12 +++- frontend/src/app/shared/shared.module.ts | 3 + 6 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.html create mode 100644 frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.scss create mode 100644 frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts diff --git a/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.html b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.html new file mode 100644 index 000000000..bf0080344 --- /dev/null +++ b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.html @@ -0,0 +1,5 @@ +
+
+ + +
+
\ No newline at end of file diff --git a/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.scss b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.scss new file mode 100644 index 000000000..35f6e32d5 --- /dev/null +++ b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.scss @@ -0,0 +1,45 @@ +.sparkles { + position: absolute; + top: var(--block-size); + height: 50px; + right: 0; +} + +.sparkle { + position: absolute; + color: rgba(152, 88, 255, 0.75); + opacity: 0; + transform: scale(0.8) rotate(0deg); + animation: pop ease 2000ms forwards, sparkle ease 500ms infinite; +} + +.inner-sparkle { + display: block; +} + +@keyframes pop { + 0% { + transform: scale(0.8) rotate(0deg); + opacity: 0; + } + 20% { + transform: scale(1) rotate(72deg); + opacity: 1; + } + 100% { + transform: scale(0) rotate(360deg); + opacity: 0; + } +} + +@keyframes sparkle { + 0% { + color: rgba(152, 88, 255, 0.75); + } + 50% { + color: rgba(198, 162, 255, 0.75); + } + 100% { + color: rgba(152, 88, 255, 0.75); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts new file mode 100644 index 000000000..bde7eb8ed --- /dev/null +++ b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts @@ -0,0 +1,71 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; + +@Component({ + selector: 'app-acceleration-sparkles', + templateUrl: './acceleration-sparkles.component.html', + styleUrls: ['./acceleration-sparkles.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AccelerationSparklesComponent implements OnChanges { + @Input() arrow: ElementRef; + @Input() run: boolean = false; + + @ViewChild('sparkleAnchor') + sparkleAnchor: ElementRef; + + constructor( + private cd: ChangeDetectorRef, + ) {} + + endTimeout: any; + lastSparkle: number = 0; + sparkleWidth: number = 0; + sparkles: any[] = []; + + ngOnChanges(changes: SimpleChanges): void { + if (changes.run) { + if (this.endTimeout) { + clearTimeout(this.endTimeout); + this.endTimeout = null; + } + if (this.run) { + this.doSparkle(); + } else { + this.endTimeout = setTimeout(() => { + this.sparkles = []; + }, 2000); + } + } + } + + doSparkle(): void { + if (this.run) { + const now = performance.now(); + if (now - this.lastSparkle > 30) { + this.lastSparkle = now; + if (this.arrow?.nativeElement && this.sparkleAnchor?.nativeElement) { + const anchor = this.sparkleAnchor.nativeElement.getBoundingClientRect().right; + const right = this.arrow.nativeElement.getBoundingClientRect().right; + const dx = (anchor - right) + 37.5; + this.sparkles.push({ + style: { + right: dx + 'px', + top: (Math.random() * 30) + 'px', + animationDelay: (Math.random() * 50) + 'ms', + }, + rotation: { + transform: `rotate(${Math.random() * 360}deg)`, + } + }); + while (this.sparkles.length > 100) { + this.sparkles.shift(); + } + this.cd.markForCheck(); + } + } + requestAnimationFrame(() => { + this.doSparkle(); + }); + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 24f229598..b979e032b 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -51,7 +51,8 @@ -
+ +
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 13608bb73..a0958ec40 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; import { Subscription, Observable, of, combineLatest } from 'rxjs'; import { MempoolBlock } from '../../interfaces/websocket.interface'; import { StateService } from '../../services/state.service'; @@ -77,6 +77,9 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { maxArrowPosition = 0; rightPosition = 0; transition = 'background 2s, right 2s, transform 1s'; + @ViewChild('arrowUp') + arrowElement: ElementRef; + acceleratingArrow: boolean = false; markIndex: number; txPosition: MempoolPosition; @@ -201,6 +204,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { this.markBlocksSubscription = this.stateService.markBlock$ .subscribe((state) => { + const oldTxPosition = this.txPosition; this.markIndex = undefined; this.txPosition = undefined; this.txFeePerVSize = undefined; @@ -209,6 +213,12 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { } if (state.mempoolPosition) { this.txPosition = state.mempoolPosition; + if (this.txPosition.accelerated && !oldTxPosition.accelerated) { + this.acceleratingArrow = true; + setTimeout(() => { + this.acceleratingArrow = false; + }, 2000); + } } if (state.txFeePerVSize) { this.txFeePerVSize = state.txFeePerVSize; diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 89bcfafbb..2d5b4d0f9 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -100,6 +100,7 @@ import { MempoolErrorComponent } from './components/mempool-error/mempool-error. import { AccelerationsListComponent } from '../components/acceleration/accelerations-list/accelerations-list.component'; import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component'; import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component'; +import { AccelerationSparklesComponent } from '../components/acceleration/sparkles/acceleration-sparkles.component'; import { BlockViewComponent } from '../components/block-view/block-view.component'; import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component'; @@ -225,6 +226,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir AccelerationsListComponent, AccelerationStatsComponent, PendingStatsComponent, + AccelerationSparklesComponent, HttpErrorComponent, TwitterWidgetComponent, FaucetComponent, @@ -355,6 +357,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir AccelerationsListComponent, AccelerationStatsComponent, PendingStatsComponent, + AccelerationSparklesComponent, HttpErrorComponent, TwitterWidgetComponent, TwitterLogin, From 021f0b32a13e97b317781be523502ee96a81efed Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 11 Aug 2024 20:52:26 +0000 Subject: [PATCH 2/2] sparklier sparkles --- .../acceleration-sparkles.component.ts | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts index bde7eb8ed..2316c996d 100644 --- a/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts +++ b/frontend/src/app/components/acceleration/sparkles/acceleration-sparkles.component.ts @@ -41,23 +41,25 @@ export class AccelerationSparklesComponent implements OnChanges { doSparkle(): void { if (this.run) { const now = performance.now(); - if (now - this.lastSparkle > 30) { + if (now - this.lastSparkle > 20) { this.lastSparkle = now; if (this.arrow?.nativeElement && this.sparkleAnchor?.nativeElement) { const anchor = this.sparkleAnchor.nativeElement.getBoundingClientRect().right; const right = this.arrow.nativeElement.getBoundingClientRect().right; - const dx = (anchor - right) + 37.5; - this.sparkles.push({ - style: { - right: dx + 'px', - top: (Math.random() * 30) + 'px', - animationDelay: (Math.random() * 50) + 'ms', - }, - rotation: { - transform: `rotate(${Math.random() * 360}deg)`, - } - }); - while (this.sparkles.length > 100) { + const dx = (anchor - right) + 30; + const numSparkles = Math.ceil(Math.random() * 3); + for (let i = 0; i < numSparkles; i++) { + this.sparkles.push({ + style: { + right: (dx + (Math.random() * 10)) + 'px', + top: (15 + (Math.random() * 30)) + 'px', + }, + rotation: { + transform: `rotate(${Math.random() * 360}deg)`, + } + }); + } + while (this.sparkles.length > 200) { this.sparkles.shift(); } this.cd.markForCheck();