From 46a2854f670f3d77a9a54b521bd63c160f00cf41 Mon Sep 17 00:00:00 2001 From: Miguel Medeiros Date: Tue, 9 Nov 2021 22:25:03 -0300 Subject: [PATCH 1/2] Add taproot activation fireworks. --- frontend/src/app/app.constants.ts | 10 ++ .../blockchain-blocks.component.html | 2 +- .../blockchain-blocks.component.scss | 34 ++++- .../blockchain-blocks.component.ts | 5 +- .../app/components/start/start.component.html | 7 + .../app/components/start/start.component.scss | 141 +++++++++++++++++- .../app/components/start/start.component.ts | 49 +++++- 7 files changed, 239 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index e9a6b6e24..a680d45f6 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -129,3 +129,13 @@ export const languages: Language[] = [ { code: 'vi', name: 'Tiếng Việt' }, // Vietnamese { code: 'zh', name: '中文' }, // Chinese ]; + + +export const specialBlocks = { + '708998': { + labelEvent: '🌱 Taproot Activated!', + }, + '840000': { + labelEvent: '🥳 Halving Event!', + } +}; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index d04d55b8d..f87aa1c99 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -1,6 +1,6 @@
-
+
 
{{ block.height }} diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index 4f9657ad4..c0e172059 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -111,7 +111,7 @@ .flashing { animation: opacityPulse 2s ease-out; - animation-iteration-count: infinite; + animation-iteration-count: infinite; opacity: 1; } @@ -119,4 +119,34 @@ 0% {opacity: 0.7;} 50% {opacity: 1.0;} 100% {opacity: 0.7;} -} \ No newline at end of file +} + +// Blinking block +@keyframes shadowyBackground { + 0% { + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transform: rotate(0deg) translateY(0px); + } + 25% { + transform: rotate(3deg) translateY(5px); + } + 50% { + box-shadow: -10px -15px 75px rgba(#5E35B1, .3); + transform: rotate(0deg) translateY(0px); + } + 75% { + transform: rotate(-3deg) translateY(5px); + } + 100% { + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transform: rotate(0deg); + } +} + +.blink-bg { + color: #fff; + background: repeating-linear-gradient(rgb(45, 51, 72), rgb(45, 51, 72) 0.163525%, rgb(16, 95, 176) 100%, rgb(147, 57, 244) 0.163525%) !important; + animation: shadowyBackground 1s infinite; + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transition: 100ms all ease-in; +} diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 6f7549ed5..3dcac5b78 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -1,8 +1,9 @@ -import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; import { Observable, Subscription } from 'rxjs'; import { Block } from 'src/app/interfaces/electrs.interface'; import { StateService } from 'src/app/services/state.service'; import { Router } from '@angular/router'; +import { specialBlocks } from 'src/app/app.constants'; @Component({ selector: 'app-blockchain-blocks', @@ -11,7 +12,7 @@ import { Router } from '@angular/router'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class BlockchainBlocksComponent implements OnInit, OnDestroy { - + specialBlocks = specialBlocks; network = ''; blocks: Block[] = []; emptyBlocks: Block[] = this.mountEmptyBlocks(); diff --git a/frontend/src/app/components/start/start.component.html b/frontend/src/app/components/start/start.component.html index 4ee2258f4..e0a3447c6 100644 --- a/frontend/src/app/components/start/start.component.html +++ b/frontend/src/app/components/start/start.component.html @@ -1,3 +1,10 @@ + +
+
+
+
+
{{ eventName }}
+
diff --git a/frontend/src/app/components/start/start.component.scss b/frontend/src/app/components/start/start.component.scss index 0392719ac..d3268c199 100644 --- a/frontend/src/app/components/start/start.component.scss +++ b/frontend/src/app/components/start/start.component.scss @@ -7,5 +7,144 @@ } #blockchain-container::-webkit-scrollbar { - display: none; + display: none; +} + +.warning-label { + position: absolute; + width: 150px; + text-align: center; + font-weight: bold; + font-size: 12px; + padding: 6px 4px; + border-radius: 4px; + margin-top: -10px; + margin-left: 10px; +} +// Fireworks + +$particles: 50; +$width: 500; +$height: 500; + +// Create the explosion... +$box-shadow: (); +$box-shadow2: (); +@for $i from 0 through $particles { + $box-shadow: $box-shadow, + random($width)-$width / 2 + px + random($height)-$height / 1.2 + px + hsl(random(360), 100, 50); + $box-shadow2: $box-shadow2, 0 0 #fff +} +@mixin keyframes ($animationName) { + @-webkit-keyframes #{$animationName} { + @content; + } + + @-moz-keyframes #{$animationName} { + @content; + } + + @-o-keyframes #{$animationName} { + @content; + } + + @-ms-keyframes #{$animationName} { + @content; + } + + @keyframes #{$animationName} { + @content; + } +} + +@mixin animation-delay ($settings) { + -moz-animation-delay: $settings; + -webkit-animation-delay: $settings; + -o-animation-delay: $settings; + -ms-animation-delay: $settings; + animation-delay: $settings; +} + +@mixin animation-duration ($settings) { + -moz-animation-duration: $settings; + -webkit-animation-duration: $settings; + -o-animation-duration: $settings; + -ms-animation-duration: $settings; + animation-duration: $settings; +} + +@mixin animation ($settings) { + -moz-animation: $settings; + -webkit-animation: $settings; + -o-animation: $settings; + -ms-animation: $settings; + animation: $settings; +} + +@mixin transform ($settings) { + transform: $settings; + -moz-transform: $settings; + -webkit-transform: $settings; + -o-transform: $settings; + -ms-transform: $settings; +} + +body { + margin:0; + padding:0; + background: #000; + overflow: hidden; +} + +.pyro > .before, .pyro > .after { + z-index: 100; + position: absolute; + width: 5px; + height: 5px; + border-radius: 50%; + box-shadow: $box-shadow2; + @include animation((1s bang ease-out infinite backwards, 1s gravity ease-in infinite backwards, 5s position linear infinite backwards)); +} + +.pyro > .after { + @include animation-delay((1.25s, 1.25s, 1.25s)); + @include animation-duration((1.25s, 1.25s, 6.25s)); +} + +@include keyframes(bang) { + to { + box-shadow:$box-shadow; + } +} + +@include keyframes(gravity) { + to { + @include transform(translateY(200px)); + opacity: 0; + } +} + +@include keyframes(position) { + 0%, 19.9% { + margin-top: 10%; + margin-left: 40%; + } + 20%, 39.9% { + margin-top: 40%; + margin-left: 30%; + } + 40%, 59.9% { + margin-top: 20%; + margin-left: 70% + } + 60%, 79.9% { + margin-top: 30%; + margin-left: 20%; + } + 80%, 99.9% { + margin-top: 30%; + margin-left: 80%; + } } diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index 2a2b7ca01..09aaa2784 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -1,10 +1,53 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { WebsocketService } from 'src/app/services/websocket.service'; +import { StateService } from 'src/app/services/state.service'; +import { specialBlocks } from 'src/app/app.constants'; @Component({ selector: 'app-start', templateUrl: './start.component.html', styleUrls: ['./start.component.scss'], }) -export class StartComponent { - constructor() { } +export class StartComponent implements OnInit { + + interval = 60; + colors = ['#5E35B1', '#ffffff']; + + specialEvent = false; + eventName = ''; + optionsLeft = { + particleCount: 2, + angle: 70, + spread: 50, + origin: { x: 0 }, + colors: this.colors, + }; + optionsRight = { + particleCount: 2, + angle: 110, + spread: 50, + origin: { x: 1 }, + colors: this.colors, + }; + + constructor( + private websocketService: WebsocketService, + private stateService: StateService, + ) { } + + ngOnInit() { + this.websocketService.want(['blocks', 'stats', 'mempool-blocks']); + this.stateService.blocks$ + .subscribe((blocks: any) => { + const block = blocks[0]; + if(specialBlocks[block.height]) { + this.specialEvent = true; + this.eventName = specialBlocks[block.height].labelEvent; + setTimeout(() => { + this.specialEvent = false; + }, 60 * 60 * 1000); + } + }); + } + } From a3de75ebf4b23083ba3be6b00cd535430cac1a45 Mon Sep 17 00:00:00 2001 From: Miguel Medeiros Date: Thu, 11 Nov 2021 15:49:47 -0300 Subject: [PATCH 2/2] Add mempool special block animation. --- frontend/src/app/app.constants.ts | 7 ++- .../blockchain-blocks.component.scss | 30 ------------- .../mempool-blocks.component.html | 4 +- .../mempool-blocks.component.scss | 20 ++++----- .../mempool-blocks.component.ts | 44 ++++++++++--------- .../src/app/interfaces/websocket.interface.ts | 2 + frontend/src/styles.scss | 32 ++++++++++++++ 7 files changed, 72 insertions(+), 67 deletions(-) diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index a680d45f6..e18f223c2 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -130,12 +130,11 @@ export const languages: Language[] = [ { code: 'zh', name: '中文' }, // Chinese ]; - export const specialBlocks = { - '708998': { - labelEvent: '🌱 Taproot Activated!', + '709632': { + labelEvent: '🌱 Taproot activated!', }, '840000': { - labelEvent: '🥳 Halving Event!', + labelEvent: '🥳 Halving', } }; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index c0e172059..569f464a5 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -120,33 +120,3 @@ 50% {opacity: 1.0;} 100% {opacity: 0.7;} } - -// Blinking block -@keyframes shadowyBackground { - 0% { - box-shadow: -10px -15px 75px rgba(#5E35B1, 1); - transform: rotate(0deg) translateY(0px); - } - 25% { - transform: rotate(3deg) translateY(5px); - } - 50% { - box-shadow: -10px -15px 75px rgba(#5E35B1, .3); - transform: rotate(0deg) translateY(0px); - } - 75% { - transform: rotate(-3deg) translateY(5px); - } - 100% { - box-shadow: -10px -15px 75px rgba(#5E35B1, 1); - transform: rotate(0deg); - } -} - -.blink-bg { - color: #fff; - background: repeating-linear-gradient(rgb(45, 51, 72), rgb(45, 51, 72) 0.163525%, rgb(16, 95, 176) 100%, rgb(147, 57, 244) 0.163525%) !important; - animation: shadowyBackground 1s infinite; - box-shadow: -10px -15px 75px rgba(#5E35B1, 1); - transition: 100ms all ease-in; -} 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 3c2f599df..de28df624 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -1,8 +1,8 @@
-
+
-
+
 
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss index 5db365452..92c40c73b 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss @@ -18,7 +18,7 @@ .flashing { animation: opacityPulse 2s ease-out; - animation-iteration-count: infinite; + animation-iteration-count: infinite; opacity: 1; } @@ -60,7 +60,7 @@ } .bitcoin-block::after { - content: ''; + content: ''; width: 125px; height: 24px; position:absolute; @@ -68,7 +68,7 @@ left: -20px; background-color: #232838; transform:skew(40deg); - transform-origin:top; + transform-origin:top; } .bitcoin-block::before { @@ -78,18 +78,18 @@ position: absolute; top: -12px; left: -20px; - background-color: #191c27; - + background-color: #191c27; + transform: skewY(50deg); - transform-origin: top; + transform-origin: top; } .mempool-block.bitcoin-block::after { - background-color: #403834; + background-color: #403834; } .mempool-block.bitcoin-block::before { - background-color: #2d2825; + background-color: #2d2825; } .black-background { @@ -102,8 +102,8 @@ position: relative; right: 75px; top: 140px; - width: 0; - height: 0; + width: 0; + height: 0; border-left: 35px solid transparent; border-right: 35px solid transparent; border-bottom: 35px solid #FFF; 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 d75ae4409..1cc83ad52 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -5,6 +5,8 @@ import { StateService } from 'src/app/services/state.service'; import { Router } from '@angular/router'; import { take, map, switchMap, share } from 'rxjs/operators'; import { feeLevels, mempoolFeeColors } from 'src/app/app.constants'; +import { specialBlocks } from 'src/app/app.constants'; +import { Block } from 'src/app/interfaces/electrs.interface'; @Component({ selector: 'app-mempool-blocks', @@ -13,12 +15,13 @@ import { feeLevels, mempoolFeeColors } from 'src/app/app.constants'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class MempoolBlocksComponent implements OnInit, OnDestroy { - + specialBlocks = specialBlocks; mempoolBlocks: MempoolBlock[] = []; mempoolEmptyBlocks: MempoolBlock[] = this.mountEmptyBlocks(); mempoolBlocks$: Observable; timeAvg$: Observable; loadingBlocks$: Observable; + blocksSubscription: Subscription; mempoolBlocksFull: MempoolBlock[] = []; mempoolBlockStyles = []; @@ -74,26 +77,25 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { fromEvent(window, 'resize') ) .pipe( - switchMap(() => this.stateService.mempoolBlocks$), - map((blocks) => { - if (!blocks.length) { - return [{ index: 0, blockSize: 0, blockVSize: 0, feeRange: [0, 0], medianFee: 0, nTx: 0, totalFees: 0 }]; - } - return blocks; - }), - map((blocks) => { - blocks.forEach((block, i) => { - block.index = this.blockIndex + i; - }); - const stringifiedBlocks = JSON.stringify(blocks); - this.mempoolBlocksFull = JSON.parse(stringifiedBlocks); - this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(stringifiedBlocks)); - this.updateMempoolBlockStyles(); - this.calculateTransactionPosition(); - return this.mempoolBlocks; - }) - ); + switchMap(() => combineLatest([ + this.stateService.blocks$.pipe(map(([block]) => block)), + this.stateService.mempoolBlocks$ + ])), + map(([lastBlock, mempoolBlocks]) => { + mempoolBlocks.forEach((block, i) => { + block.index = this.blockIndex + i; + block.height = lastBlock.height + i + 1; + block.blink = specialBlocks[block.height] ? true : false; + }); + const stringifiedBlocks = JSON.stringify(mempoolBlocks); + this.mempoolBlocksFull = JSON.parse(stringifiedBlocks); + this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(stringifiedBlocks)); + this.updateMempoolBlockStyles(); + this.calculateTransactionPosition(); + return this.mempoolBlocks; + }) + ); this.timeAvg$ = timer(0, 1000) .pipe( @@ -118,7 +120,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { } else { timeAvgMins += Math.abs(timeAvgDiff); } - + return timeAvgMins * 60 * 1000; }) ); diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index e4e31b942..989c4176b 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -26,6 +26,8 @@ export interface WebsocketResponse { } export interface MempoolBlock { + blink?: boolean; + height?: number; blockSize: number; blockVSize: number; nTx: number; diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 4549b4d5d..91f981ba9 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -941,3 +941,35 @@ th { width: 220px; } } + + + +// Blinking block +@keyframes shadowyBackground { + 0% { + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transform: rotate(0deg) translateY(0px); + } + 25% { + transform: rotate(3deg) translateY(5px); + } + 50% { + box-shadow: -10px -15px 75px rgba(#5E35B1, .3); + transform: rotate(0deg) translateY(0px); + } + 75% { + transform: rotate(-3deg) translateY(5px); + } + 100% { + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transform: rotate(0deg); + } +} + +.blink-bg { + color: #fff; + background: repeating-linear-gradient(rgb(45, 51, 72), rgb(45, 51, 72) 0.163525%, rgb(16, 95, 176) 100%, rgb(147, 57, 244) 0.163525%) !important; + animation: shadowyBackground 1s infinite; + box-shadow: -10px -15px 75px rgba(#5E35B1, 1); + transition: 100ms all ease-in; +}