From 6b481d5a07d3d54bfd306dd5eee8e653d422324f Mon Sep 17 00:00:00 2001 From: natsoni Date: Thu, 4 Jul 2024 16:54:35 +0900 Subject: [PATCH] Add acceleration timeline --- .../acceleration-timeline.component.html | 78 +++++++ .../acceleration-timeline.component.scss | 197 ++++++++++++++++++ .../acceleration-timeline.component.ts | 33 +++ .../transaction/transaction.component.html | 9 + frontend/src/app/shared/shared.module.ts | 3 + 5 files changed, 320 insertions(+) create mode 100644 frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html create mode 100644 frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss create mode 100644 frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html new file mode 100644 index 000000000..6d3591fb9 --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html @@ -0,0 +1,78 @@ +
+
+
+
+
+
+
+ +
+
+
+
+
+ @if (eta) { + ~ + } @else if (tx.status.block_time) { + + } +
+
+
+
+ +
+
+
+
+ +
+
+
Sent
+
+ +
+
+
+
+
+
+
+
+ +
+
+
Accelerated
+
+ +
+
+
+
+
+
+
+ +
+
+
Mined
+
+ @if (tx.status.block_time) { + + } @else if (eta) { + + } +
+
+
+
+ + +
+
+ + +
+
+ +
\ No newline at end of file diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss new file mode 100644 index 000000000..d0338ec84 --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss @@ -0,0 +1,197 @@ +.acceleration-timeline { + position: relative; + width: 100%; + padding: 1em 0; + + &::after, &::before { + content: ''; + display: block; + position: absolute; + top: 0; + bottom: 0; + width: 2em; + z-index: 2; + } + + &::before { + left: 0; + background: linear-gradient(to right, var(--box-bg), var(--box-bg), transparent); + } + + &::after { + right: 0; + background: linear-gradient(to left, var(--box-bg), var(--box-bg), transparent); + } + + .timeline-wrapper { + position: relative; + width: calc(100% - 2em); + margin: auto; + overflow-x: auto; + -ms-overflow-style: none; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .intervals, .nodes { + min-width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + text-align: center; + + .node, .node-spacer { + width: 6em; + min-width: 6em; + flex-grow: 1; + } + + .interval, .interval-spacer { + width: 8em; + min-width: 5em; + max-width: 8em; + height: 32px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-end; + } + + .interval { + overflow: visible; + } + + .interval-time { + font-size: 12px; + line-height: 16px; + white-space: nowrap; + } + } + + .node, .interval-spacer { + position: relative; + .seen-to-acc { + position: absolute; + height: 10px; + left: -5px; + right: -5px; + top: 0; + transform: translateY(-50%); + background: var(--primary); + border-radius: 5px; + + &.loading { + animation: standardPulse 1s infinite; + } + + &.left { + right: 50%; + } + + &.right { + left: 50%; + } + } + + .acc-to-confirmed { + position: absolute; + height: 10px; + left: -5px; + right: -5px; + top: 0; + transform: translateY(-50%); + background: var(--tertiary); + border-radius: 5px; + + &.loading { + animation: acceleratePulse 1s infinite; + } + + &.left { + right: 50%; + } + &.right { + left: 50%; + } + } + + } + + .nodes { + position: relative; + margin-top: 1em; + .node { + .shape-border { + display: block; + margin: auto; + height: calc(1em + 8px); + width: calc(1em + 8px); + margin-bottom: -8px; + transform: translateY(-50%); + border-radius: 50%; + padding: 2px; + background: transparent; + transition: background-color 300ms, padding 300ms; + + .shape { + width: 100%; + height: 100%; + border-radius: 50%; + background: white; + transition: background-color 300ms, border 300ms; + } + + &.sent-selected { + .shape { + background: var(--primary); + } + } + + &.accelerated-selected { + .shape { + background: var(--tertiary); + } + } + + &.mined-selected { + .shape { + background: var(--success); + } + } + } + + .status { + margin-top: -64px; + + .badge.badge-accelerated { + background-color: var(--tertiary); + color: white; + } + } + + .time { + margin-top: 33px; + font-size: 12px; + line-height: 16px; + white-space: nowrap; + } + } + } +} + +@keyframes acceleratePulse { + 0% { background-color: var(--tertiary) } + 50% { background-color: var(--mainnet-alt) } + 100% { background-color: var(--tertiary) } +} + +@keyframes standardPulse { + 0% { background-color: var(--primary) } + 50% { background-color: var(--secondary) } + 100% { background-color: var(--primary) } + +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts new file mode 100644 index 000000000..d40215c1d --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts @@ -0,0 +1,33 @@ +import { Component, Input, OnInit, OnChanges, Inject, LOCALE_ID } from '@angular/core'; +import { ETA } from '../../services/eta.service'; +import { Transaction } from '../../interfaces/electrs.interface'; + +@Component({ + selector: 'app-acceleration-timeline', + templateUrl: './acceleration-timeline.component.html', + styleUrls: ['./acceleration-timeline.component.scss'], +}) +export class AccelerationTimelineComponent implements OnInit, OnChanges { + @Input() transactionTime: number; + @Input() tx: Transaction; + @Input() eta: ETA; + + acceleratedAt: number; + dir: 'rtl' | 'ltr' = 'ltr'; + + constructor( + @Inject(LOCALE_ID) private locale: string, + ) { + if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { + this.dir = 'rtl'; + } + } + + ngOnInit(): void { + this.acceleratedAt = this.tx.acceleratedAt ?? new Date().getTime() / 1000; + } + + ngOnChanges(changes): void { + } + +} diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 8967e03b8..0d98a30a8 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -152,6 +152,15 @@
+ +
+

Acceleration Timeline

+
+
+ +
+
+

RBF History

diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index c060bbbd2..868cb1bd9 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -66,6 +66,7 @@ import { DifficultyMiningComponent } from '../components/difficulty-mining/diffi import { BalanceWidgetComponent } from '../components/balance-widget/balance-widget.component'; import { AddressTransactionsWidgetComponent } from '../components/address-transactions-widget/address-transactions-widget.component'; import { RbfTimelineComponent } from '../components/rbf-timeline/rbf-timeline.component'; +import { AccelerationTimelineComponent } from '../components/acceleration-timeline/acceleration-timeline.component'; import { RbfTimelineTooltipComponent } from '../components/rbf-timeline/rbf-timeline-tooltip.component'; import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component'; import { TestTransactionsComponent } from '../components/test-transactions/test-transactions.component'; @@ -177,6 +178,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir BalanceWidgetComponent, AddressTransactionsWidgetComponent, RbfTimelineComponent, + AccelerationTimelineComponent, RbfTimelineTooltipComponent, PushTransactionComponent, TestTransactionsComponent, @@ -316,6 +318,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir BalanceWidgetComponent, AddressTransactionsWidgetComponent, RbfTimelineComponent, + AccelerationTimelineComponent, RbfTimelineTooltipComponent, PushTransactionComponent, TestTransactionsComponent,