Restyle transaction preview diagram
This commit is contained in:
parent
fafe40cef0
commit
626b4e61cd
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
<div class="page-title">
|
<div class="page-title">
|
||||||
<h1 i18n="shared.transaction">Transaction</h1>
|
<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">
|
<div *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" class="features">
|
||||||
<app-tx-features [tx]="tx"></app-tx-features>
|
<app-tx-features [tx]="tx"></app-tx-features>
|
||||||
<span *ngIf="cpfpInfo && cpfpInfo.bestDescendant" class="badge badge-primary mr-1">
|
<span *ngIf="cpfpInfo && cpfpInfo.bestDescendant" class="badge badge-primary mr-1">
|
||||||
@ -13,21 +16,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-center mb-0">
|
<div class="top-data row">
|
||||||
<a [routerLink]="['/tx/' | relativeUrl, txId]" class="tx-link">
|
<span class="field col-sm-4 text-left">
|
||||||
{{ txId }}
|
<ng-template [ngIf]="isLiquid && haveBlindedOutputValues(tx)" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
|
||||||
</a>
|
<ng-template #defaultAmount>
|
||||||
</p>
|
<app-amount [satoshis]="totalValue"></app-amount>
|
||||||
|
</ng-template>
|
||||||
|
</span>
|
||||||
|
<span class="field col-sm-4 text-center">‎{{ (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">
|
<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">
|
<div class="above-bow">
|
||||||
<p class="field">
|
<p class="field pair">
|
||||||
<ng-template [ngIf]="isLiquid && haveBlindedOutputValues(tx)" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
|
<span [innerHTML]="'‎' + (tx.size | bytes: 2)"></span>
|
||||||
<ng-template #defaultAmount>
|
<span [innerHTML]="'‎' + (tx.weight | wuBytes: 2)"></span>
|
||||||
<app-amount [satoshis]="totalValue"></app-amount>
|
|
||||||
</ng-template>
|
|
||||||
</p>
|
</p>
|
||||||
<p class="field" *ngIf="!isCoinbase(tx)">
|
<p class="field" *ngIf="!isCoinbase(tx)">
|
||||||
{{ tx.feePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
{{ tx.feePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
|
@ -10,26 +10,10 @@
|
|||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-small-height {
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow-green {
|
|
||||||
color: #1a9436;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow-red {
|
|
||||||
color: #dc3545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
.effective-fee-container {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
h2 {
|
h2 {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@ -46,8 +30,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: baseline;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 2px;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 52px;
|
font-size: 52px;
|
||||||
@ -58,6 +43,43 @@
|
|||||||
.features {
|
.features {
|
||||||
font-size: 24px;
|
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 {
|
.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 {
|
.tx-link {
|
||||||
display: inline;
|
display: inline;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
@ -87,15 +126,6 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
.field {
|
|
||||||
font-size: 32px;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
::ng-deep .symbol {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlaid {
|
.overlaid {
|
||||||
|
@ -29,6 +29,7 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
|
|||||||
isLoadingTx = true;
|
isLoadingTx = true;
|
||||||
error: any = undefined;
|
error: any = undefined;
|
||||||
errorUnblinded: any = undefined;
|
errorUnblinded: any = undefined;
|
||||||
|
transactionTime = -1;
|
||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
fetchCpfpSubscription: Subscription;
|
fetchCpfpSubscription: Subscription;
|
||||||
cpfpInfo: CpfpInfo | null;
|
cpfpInfo: CpfpInfo | null;
|
||||||
@ -163,6 +164,12 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
|
|||||||
this.opReturns = this.getOpReturns(this.tx);
|
this.opReturns = this.getOpReturns(this.tx);
|
||||||
this.extraData = this.chooseExtraData();
|
this.extraData = this.chooseExtraData();
|
||||||
|
|
||||||
|
if (!tx.status.confirmed && tx.firstSeen) {
|
||||||
|
this.transactionTime = tx.firstSeen;
|
||||||
|
} else {
|
||||||
|
this.getTransactionTime();
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.tx.status.confirmed) {
|
if (!this.tx.status.confirmed) {
|
||||||
if (tx.cpfpChecked) {
|
if (tx.cpfpChecked) {
|
||||||
this.cpfpInfo = {
|
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() {
|
resetTransaction() {
|
||||||
this.error = undefined;
|
this.error = undefined;
|
||||||
this.tx = null;
|
this.tx = null;
|
||||||
this.isLoadingTx = true;
|
this.isLoadingTx = true;
|
||||||
|
this.transactionTime = -1;
|
||||||
this.cpfpInfo = null;
|
this.cpfpInfo = null;
|
||||||
this.showCpfpDetails = false;
|
this.showCpfpDetails = false;
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
markerUnits="strokeWidth"
|
markerUnits="strokeWidth"
|
||||||
markerWidth="1.5" markerHeight="1"
|
markerWidth="1.5" markerHeight="1"
|
||||||
orient="auto">
|
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>
|
||||||
<marker id="output-arrow" viewBox="-5 -5 10 10"
|
<marker id="output-arrow" viewBox="-5 -5 10 10"
|
||||||
refX="0" refY="0"
|
refX="0" refY="0"
|
||||||
markerUnits="strokeWidth"
|
markerUnits="strokeWidth"
|
||||||
markerWidth="1.5" markerHeight="1"
|
markerWidth="1.5" markerHeight="1"
|
||||||
orient="auto">
|
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>
|
||||||
<marker id="fee-arrow" viewBox="-5 -5 10 10"
|
<marker id="fee-arrow" viewBox="-5 -5 10 10"
|
||||||
refX="0" refY="0"
|
refX="0" refY="0"
|
||||||
@ -20,9 +20,17 @@
|
|||||||
markerWidth="1.5" markerHeight="1"
|
markerWidth="1.5" markerHeight="1"
|
||||||
orient="auto">
|
orient="auto">
|
||||||
</marker>
|
</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%">
|
<linearGradient id="fee-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
<stop offset="0%" stop-color="white" />
|
<stop offset="0%" [attr.stop-color]="gradient[1]" />
|
||||||
<stop offset="50%" stop-color="white" />
|
<stop offset="50%" [attr.stop-color]="gradient[1]" />
|
||||||
<stop offset="100%" stop-color="transparent" />
|
<stop offset="100%" stop-color="transparent" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.0 KiB |
@ -1,6 +1,15 @@
|
|||||||
.bowtie {
|
.bowtie {
|
||||||
.line {
|
.line {
|
||||||
stroke: white;
|
|
||||||
fill: none;
|
fill: none;
|
||||||
|
|
||||||
|
&.input {
|
||||||
|
stroke: url(#input-gradient);
|
||||||
|
}
|
||||||
|
&.output {
|
||||||
|
stroke: url(#output-gradient);
|
||||||
|
}
|
||||||
|
&.fee {
|
||||||
|
stroke: url(#fee-gradient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ interface SvgLine {
|
|||||||
})
|
})
|
||||||
export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||||
@Input() tx: Transaction;
|
@Input() tx: Transaction;
|
||||||
@Input() isLiquid: boolean = false;
|
@Input() network: string;
|
||||||
@Input() width = 1200;
|
@Input() width = 1200;
|
||||||
@Input() height = 600;
|
@Input() height = 600;
|
||||||
@Input() combinedWeight = 100;
|
@Input() combinedWeight = 100;
|
||||||
@ -24,12 +24,32 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
inputs: SvgLine[];
|
inputs: SvgLine[];
|
||||||
outputs: SvgLine[];
|
outputs: SvgLine[];
|
||||||
middle: 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 {
|
ngOnInit(): void {
|
||||||
|
this.isLiquid = (this.network === 'liquid' || this.network === 'liquidtestnet');
|
||||||
|
this.gradient = this.gradientColors[this.network];
|
||||||
this.initGraph();
|
this.initGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
|
this.isLiquid = (this.network === 'liquid' || this.network === 'liquidtestnet');
|
||||||
|
this.gradient = this.gradientColors[this.network];
|
||||||
this.initGraph();
|
this.initGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +66,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
this.middle = {
|
this.middle = {
|
||||||
path: `M ${(this.width / 2) - 50} ${(this.height / 2) + 0.5} L ${(this.width / 2) + 50} ${(this.height / 2) + 0.5}`,
|
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 start = side === 'in' ? (weight * 0.5) : this.width - (weight * 0.5);
|
||||||
const center = this.width / 2 + (side === 'in' ? -45 : 45 );
|
const center = this.width / 2 + (side === 'in' ? -45 : 45 );
|
||||||
const midpoint = (start + center) / 2;
|
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}`;
|
return `M ${start} ${outer} C ${midpoint} ${outer}, ${midpoint} ${inner}, ${center} ${inner}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user