11<script setup>
2+ /** Vendor */
3+ import { DateTime } from " luxon"
4+
25/** Services */
3- import { comma , getNetworkName } from " @/services/utils"
6+ import { comma } from " @/services/utils"
47
58/** Store */
69import { useAppStore } from " @/store/app"
710const appStore = useAppStore ()
811
12+ const lastBlock = computed (() => appStore .latestBlocks [0 ])
13+
914let blockProgressInterval = null
10- const baseBlockTime = 12
11- const blockProgress = ref (0 )
15+ let delayInterval = null
1216
17+ const delay = ref (0 )
1318const isDelayed = ref (false )
1419
15- const lastBlock = computed (() => appStore .latestBlocks [0 ])
20+ const offsetSinceLastBlock = Math .abs (
21+ DateTime .fromISO (lastBlock .value .time ).diffNow (" seconds" ).values .seconds + lastBlock .value .stats .block_time / 1_000 ,
22+ )
1623
17- // const checkDelay = () => {
18- // if (-DateTime.fromISO(lastBlock.value.time).diffNow("seconds").values.seconds > 12) {
19- // isDelayed.value = true
20- // }
21- // }
24+ if (offsetSinceLastBlock > lastBlock .value .stats .block_time / 1_000 ) {
25+ isDelayed .value = true
26+ delay .value = Math .floor (offsetSinceLastBlock - lastBlock .value .stats .block_time / 1_000 )
27+ delayInterval = setInterval (() => {
28+ delay .value += 1
29+ }, 1_000 )
30+ }
2231
23- // checkDelay()
32+ const blockProgress = ref (Math .floor (offsetSinceLastBlock))
33+ const fillOffset = computed (() => {
34+ const offset = - (100 - (100 * blockProgress .value ) / (lastBlock .value .stats .block_time / 1_000 ))
35+ return offset < 0 ? offset : 0
36+ })
2437
25- blockProgressInterval = setInterval (() => {
26- blockProgress .value += 1
38+ const startBlockProgress = () => {
39+ blockProgressInterval = setInterval (() => {
40+ blockProgress .value += 1
2741
28- if (blockProgress .value > baseBlockTime) {
29- blockProgress .value = 0
30- }
31- }, 1_000 )
42+ if (blockProgress .value > lastBlock .value .stats .block_time / 1_000 + 1 ) {
43+ isDelayed .value = true
44+ clearInterval (blockProgressInterval)
3245
33- // watch(
34- // () => lastBlock.value,
35- // () => {
36- // isDelayed.value = false
46+ delayInterval = setInterval (() => {
47+ delay .value += 1
48+ }, 1_000 )
49+ }
50+ }, 1_000 )
51+ }
52+ if (! isDelayed .value ) startBlockProgress ()
3753
38- // },
39- // )
54+ watch (
55+ () => lastBlock .value ,
56+ () => {
57+ isDelayed .value = false
58+
59+ clearInterval (blockProgressInterval)
60+ clearInterval (delayInterval)
61+
62+ blockProgress .value = 0
63+ delay .value = 0
64+
65+ startBlockProgress ()
66+ },
67+ )
4068
4169onBeforeUnmount (() => {
4270 clearInterval (blockProgressInterval)
@@ -46,37 +74,57 @@ onBeforeUnmount(() => {
4674<template >
4775 <NuxtLink :to =" `/block/${lastBlock.height}`" :class =" $style.wrapper" >
4876 <Flex justify =" between" >
49- <Flex direction =" column" gap =" 8 " >
77+ <Flex direction =" column" gap =" 10 " >
5078 <Flex align =" center" gap =" 4" >
5179 <Text size =" 16" weight =" 600" color =" primary" > Block </Text >
5280 <Text size =" 16" weight =" 600" color =" green" > {{ comma(lastBlock.height) }}</Text >
5381 </Flex >
5482
55- <Text size =" 13" weight =" 500" color =" tertiary" > Chain {{ getNetworkName() }} </Text >
83+ <Flex align =" center" gap =" 6" >
84+ <Icon name =" time" size =" 12" color =" tertiary" :class =" $style.time_icon" />
85+ <Text size =" 12" weight =" 500" color =" tertiary" >Awaiting new block</Text >
86+ </Flex >
5687 </Flex >
5788
5889 <Flex direction =" column" gap =" 8" align =" end" >
59- <Text size =" 14" weight =" 600" color =" primary" > {{ (lastBlock.stats.block_time / 1_000).toFixed(2 ) }}s </Text >
90+ <Text size =" 14" weight =" 600" color =" primary" > ~ {{ Math.ceil (lastBlock.stats.block_time / 1_000) }}s </Text >
6091 <Text size =" 12" weight =" 500" color =" tertiary" > Block Time </Text >
6192 </Flex >
6293 </Flex >
6394
64- <Flex align =" center" justify =" between" :class =" $style.bar" >
65- <Icon name =" block" size =" 16" color =" primary" />
95+ <Flex align =" center" justify =" center" :class =" $style.bar" >
96+ <Transition name =" fade" >
97+ <svg v-if =" isDelayed" width =" 100%" height =" 28" :class =" $style.lines" >
98+ <pattern id =" diagonalHatch1" width =" 20" height =" 20" patternTransform =" rotate(45 0 0)" patternUnits =" userSpaceOnUse" >
99+ <line x1 =" 0" y1 =" 0" x2 =" 0" y2 =" 20" style =" stroke : var (--op-10 ); stroke-width : 15 " />
100+ </pattern >
101+ <rect x =" 0" y =" 0" width =" 100%" height =" 100%" fill =" url(#diagonalHatch1)" ></rect >
102+ </svg >
103+ </Transition >
104+
105+ <Flex v-if =" !isDelayed" align =" center" justify =" between" wide >
106+ <Icon name =" block" size =" 16" color =" primary" />
66107
67- <div v-for =" item in 14" :class =" $style.dot" />
108+ <div v-for =" item in 14" :class =" $style.dot" />
68109
69- <Flex v-if =" !isDelayed" justify =" end" :class =" $style.timer" >
70- <Text size =" 13" weight =" 600" color =" primary" >{{ blockProgress }}</Text >
71- <Text size =" 13" weight =" 600" color =" tertiary" >s</Text >
110+ <Flex justify =" end" :class =" $style.timer" >
111+ <Text size =" 13" weight =" 600" color =" primary" >{{ blockProgress }}</Text >
112+ <Text size =" 13" weight =" 600" color =" tertiary" >s</Text >
113+ </Flex >
114+ </Flex >
115+ <Flex v-else align =" center" gap =" 4" >
116+ <Text size =" 13" weight =" 600" color =" secondary" >Delayed by </Text >
117+ <Text size =" 13" weight =" 600" color =" primary" >{{ delay }}s</Text >
72118 </Flex >
73- <Text v-else size =" 13" weight =" 600" color =" secondary" >Delayed</Text >
74119
75- <div
76- v-if =" !isDelayed"
77- :style =" { transform: `translateX(${-(100 - (100 * blockProgress) / baseBlockTime)}%)` }"
78- :class =" $style.fill"
79- />
120+ <div v-if =" !isDelayed" :style =" { transform: `translateX(${fillOffset}%)` }" :class =" $style.fill" >
121+ <svg width =" 100%" height =" 28" :class =" $style.lines" >
122+ <pattern id =" diagonalHatch2" width =" 20" height =" 20" patternTransform =" rotate(45 0 0)" patternUnits =" userSpaceOnUse" >
123+ <line x1 =" 0" y1 =" 0" x2 =" 0" y2 =" 20" style =" stroke : var (--op-20 ); stroke-width : 15 " />
124+ </pattern >
125+ <rect x =" 0" y =" 0" width =" 100%" height =" 100%" fill =" url(#diagonalHatch2)" ></rect >
126+ </svg >
127+ </div >
80128 <div v-else :class =" [$style.fill, $style.delayed]" />
81129 </Flex >
82130 </NuxtLink >
@@ -115,11 +163,20 @@ onBeforeUnmount(() => {
115163 height : 28px ;
116164 z-index : 0 ;
117165
166+ box-shadow : 0 0 0 2px var (--op-5 );
118167 border-radius : 6px ;
119168 background : var (--block-progress-background );
120169 overflow : hidden ;
121170
122171 padding : 0 8px ;
172+
173+ .lines {
174+ position : absolute ;
175+
176+ top : 0 ;
177+ left : 0 ;
178+ bottom : 0 ;
179+ }
123180}
124181
125182.dot {
@@ -146,10 +203,36 @@ onBeforeUnmount(() => {
146203 z-index : -1 ;
147204
148205 will-change : transform;
149- transition : transform 0.9s ease ;
206+ transition : all 0.9s ease ;
150207
151208 &.delayed {
152- background : var (--txt-support );
209+ background : var (--op-10 );
210+ }
211+ }
212+
213+ .time_icon {
214+ animation : rotation 1.5s ease infinite ;
215+ }
216+
217+ @keyframes rotation {
218+ 0% {
219+ transform : rotate (0deg );
220+ }
221+
222+ 20% {
223+ transform : rotate (180deg );
224+ }
225+
226+ 30% {
227+ transform : rotate (-30deg );
228+ }
229+
230+ 50% {
231+ transform : rotate (0deg );
232+ }
233+
234+ 100% {
235+ transform : rotate (0deg );
153236 }
154237}
155238 </style >
0 commit comments