Restyle transaction preview diagram

This commit is contained in:
Mononaut 2022-08-24 18:54:11 +00:00
parent fafe40cef0
commit 626b4e61cd
No known key found for this signature in database
GPG Key ID: 61B952CAF4838F94
6 changed files with 145 additions and 45 deletions

View File

@ -2,6 +2,9 @@
<div class="page-title">
<h1 i18n="shared.transaction">Transaction</h1>
<a class="tx-link" [routerLink]="['/tx/' | relativeUrl, txId]">
<span class="truncated">{{txId.slice(0,-4)}}</span><span class="last-four">{{txId.slice(-4)}}</span>
</a>
<div *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" class="features">
<app-tx-features [tx]="tx"></app-tx-features>
<span *ngIf="cpfpInfo && cpfpInfo.bestDescendant" class="badge badge-primary mr-1">
@ -13,21 +16,24 @@
</div>
</div>
<p class="text-center mb-0">
<a [routerLink]="['/tx/' | relativeUrl, txId]" class="tx-link">
{{ txId }}
</a>
</p>
<div class="top-data row">
<span class="field col-sm-4 text-left">
<ng-template [ngIf]="isLiquid && haveBlindedOutputValues(tx)" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
<ng-template #defaultAmount>
<app-amount [satoshis]="totalValue"></app-amount>
</ng-template>
</span>
<span class="field col-sm-4 text-center">&lrm;{{ (tx.status.confirmed ? tx.status.block_time : transactionTime) * 1000 | date:'yyyy-MM-dd HH:mm' }}</span>
<span class="field col-sm-4 text-right"><span class="label" i18n="transaction.fee|Transaction fee">Fee </span>{{ tx.fee | number }} <span class="symbol" i18n="shared.sat|sat">sat</span></span>
</div>
<div class="row graph-wrapper">
<tx-bowtie-graph [tx]="tx" [width]="1112" [height]="346" [isLiquid]="isLiquid"></tx-bowtie-graph>
<tx-bowtie-graph [tx]="tx" [width]="1112" [height]="346" [network]="network"></tx-bowtie-graph>
<div class="above-bow">
<p class="field">
<ng-template [ngIf]="isLiquid && haveBlindedOutputValues(tx)" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
<ng-template #defaultAmount>
<app-amount [satoshis]="totalValue"></app-amount>
</ng-template>
<p class="field pair">
<span [innerHTML]="'&lrm;' + (tx.size | bytes: 2)"></span>
<span [innerHTML]="'&lrm;' + (tx.weight | wuBytes: 2)"></span>
</p>
<p class="field" *ngIf="!isCoinbase(tx)">
{{ tx.feePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>

View File

@ -10,26 +10,10 @@
font-size: 28px;
}
.btn-small-height {
line-height: 1.1;
}
.arrow-green {
color: #1a9436;
}
.arrow-red {
color: #dc3545;
}
.row {
flex-direction: row;
}
.effective-fee-container {
display: inline-block;
}
.title {
h2 {
line-height: 1;
@ -46,8 +30,9 @@
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
align-items: baseline;
margin-bottom: 2px;
max-width: 100%;
h1 {
font-size: 52px;
@ -58,6 +43,43 @@
.features {
font-size: 24px;
}
& > * {
flex-grow: 0;
flex-shrink: 0;
}
.tx-link {
flex-grow: 1;
flex-shrink: 1;
margin: 0 1em;
overflow: hidden;
white-space: nowrap;
display: flex;
flex-direction: row;
align-items: baseline;
.truncated {
flex-grow: 1;
flex-shrink: 1;
overflow: hidden;
text-overflow: ellipsis;
margin-right: -2px;
}
.last-four {
flex-shrink: 0;
flex-grow: 0;
}
}
.features {
align-self: center;
}
}
.top-data {
font-size: 28px;
}
.table {
@ -68,6 +90,23 @@
}
}
.field {
font-size: 32px;
margin: 0;
::ng-deep .symbol {
font-size: 24px;
}
.label {
color: #ffffff66;
}
&.pair > *:first-child {
margin-right: 1em;
}
}
.tx-link {
display: inline;
font-size: 28px;
@ -87,15 +126,6 @@
right: 0;
margin: auto;
text-align: center;
.field {
font-size: 32px;
margin: 0;
::ng-deep .symbol {
font-size: 24px;
}
}
}
.overlaid {

View File

@ -29,6 +29,7 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
isLoadingTx = true;
error: any = undefined;
errorUnblinded: any = undefined;
transactionTime = -1;
subscription: Subscription;
fetchCpfpSubscription: Subscription;
cpfpInfo: CpfpInfo | null;
@ -163,6 +164,12 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
this.opReturns = this.getOpReturns(this.tx);
this.extraData = this.chooseExtraData();
if (!tx.status.confirmed && tx.firstSeen) {
this.transactionTime = tx.firstSeen;
} else {
this.getTransactionTime();
}
if (!this.tx.status.confirmed) {
if (tx.cpfpChecked) {
this.cpfpInfo = {
@ -185,10 +192,26 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
);
}
getTransactionTime() {
this.openGraphService.waitFor('tx-time');
this.apiService
.getTransactionTimes$([this.tx.txid])
.pipe(
catchError((err) => {
return of(0);
})
)
.subscribe((transactionTimes) => {
this.transactionTime = transactionTimes[0];
this.openGraphService.waitOver('tx-time');
});
}
resetTransaction() {
this.error = undefined;
this.tx = null;
this.isLoadingTx = true;
this.transactionTime = -1;
this.cpfpInfo = null;
this.showCpfpDetails = false;
}

View File

@ -5,14 +5,14 @@
markerUnits="strokeWidth"
markerWidth="1.5" markerHeight="1"
orient="auto">
<path d="M -5 -5 L 0 0 L -5 5 L 1 5 L 1 -5 Z" stroke="white" stroke-width="0" fill="white"/>
<path d="M -5 -5 L 0 0 L -5 5 L 1 5 L 1 -5 Z" stroke-width="0" [attr.fill]="gradient[0]"/>
</marker>
<marker id="output-arrow" viewBox="-5 -5 10 10"
refX="0" refY="0"
markerUnits="strokeWidth"
markerWidth="1.5" markerHeight="1"
orient="auto">
<path d="M 1 -5 L 0 -5 L -5 0 L 0 5 L 1 5 Z" stroke="white" stroke-width="0" fill="white"/>
<path d="M 1 -5 L 0 -5 L -5 0 L 0 5 L 1 5 Z" stroke-width="0" [attr.fill]="gradient[0]"/>
</marker>
<marker id="fee-arrow" viewBox="-5 -5 10 10"
refX="0" refY="0"
@ -20,9 +20,17 @@
markerWidth="1.5" markerHeight="1"
orient="auto">
</marker>
<linearGradient id="input-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" [attr.stop-color]="gradient[0]" />
<stop offset="100%" [attr.stop-color]="gradient[1]" />
</linearGradient>
<linearGradient id="output-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" [attr.stop-color]="gradient[1]" />
<stop offset="100%" [attr.stop-color]="gradient[0]" />
</linearGradient>
<linearGradient id="fee-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="white" />
<stop offset="50%" stop-color="white" />
<stop offset="0%" [attr.stop-color]="gradient[1]" />
<stop offset="50%" [attr.stop-color]="gradient[1]" />
<stop offset="100%" stop-color="transparent" />
</linearGradient>
</defs>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,6 +1,15 @@
.bowtie {
.line {
stroke: white;
fill: none;
&.input {
stroke: url(#input-gradient);
}
&.output {
stroke: url(#output-gradient);
}
&.fee {
stroke: url(#fee-gradient);
}
}
}

View File

@ -14,7 +14,7 @@ interface SvgLine {
})
export class TxBowtieGraphComponent implements OnInit, OnChanges {
@Input() tx: Transaction;
@Input() isLiquid: boolean = false;
@Input() network: string;
@Input() width = 1200;
@Input() height = 600;
@Input() combinedWeight = 100;
@ -24,12 +24,32 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
inputs: SvgLine[];
outputs: SvgLine[];
middle: SvgLine;
isLiquid: boolean = false;
gradientColors = {
'': ['#9339f4', '#105fb0'],
bisq: ['#9339f4', '#105fb0'],
// liquid: ['#116761', '#183550'],
liquid: ['#09a197', '#0f62af'],
// 'liquidtestnet': ['#494a4a', '#272e46'],
'liquidtestnet': ['#d2d2d2', '#979797'],
// testnet: ['#1d486f', '#183550'],
testnet: ['#4edf77', '#10a0af'],
// signet: ['#6f1d5d', '#471850'],
signet: ['#d24fc8', '#a84fd2'],
};
gradient: string[] = ['#105fb0', '#105fb0'];
ngOnInit(): void {
this.isLiquid = (this.network === 'liquid' || this.network === 'liquidtestnet');
this.gradient = this.gradientColors[this.network];
this.initGraph();
}
ngOnChanges(): void {
this.isLiquid = (this.network === 'liquid' || this.network === 'liquidtestnet');
this.gradient = this.gradientColors[this.network];
this.initGraph();
}
@ -46,7 +66,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
this.middle = {
path: `M ${(this.width / 2) - 50} ${(this.height / 2) + 0.5} L ${(this.width / 2) + 50} ${(this.height / 2) + 0.5}`,
style: `stroke-width: ${this.combinedWeight + 0.5}`
style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}`
};
}
@ -132,6 +152,10 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
const start = side === 'in' ? (weight * 0.5) : this.width - (weight * 0.5);
const center = this.width / 2 + (side === 'in' ? -45 : 45 );
const midpoint = (start + center) / 2;
// correct for svg horizontal gradient bug
if (Math.round(outer) === Math.round(inner)) {
outer -= 1;
}
return `M ${start} ${outer} C ${midpoint} ${outer}, ${midpoint} ${inner}, ${center} ${inner}`;
}