Merge branch 'master' into mononaut/handle-websocket-errors

This commit is contained in:
softsimon 2023-11-30 15:18:16 +09:00 committed by GitHub
commit ed07daebca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 103648 additions and 68024 deletions

View File

@ -80,7 +80,13 @@ class ChannelsApi {
public async $searchChannelsById(search: string): Promise<any[]> { public async $searchChannelsById(search: string): Promise<any[]> {
try { try {
const searchStripped = search.replace(/[^0-9x]/g, '') + '%'; // restrict search to valid id/short_id prefix formats
let searchStripped = search.match(/[0-9]+[0-9x]*/)?.[0] || '';
if (!searchStripped.length) {
return [];
}
// add wildcard to search by prefix
searchStripped += '%';
const query = `SELECT id, short_id, capacity, status FROM channels WHERE id LIKE ? OR short_id LIKE ? LIMIT 10`; const query = `SELECT id, short_id, capacity, status FROM channels WHERE id LIKE ? OR short_id LIKE ? LIMIT 10`;
const [rows]: any = await DB.query(query, [searchStripped, searchStripped]); const [rows]: any = await DB.query(query, [searchStripped, searchStripped]);
return rows; return rows;

View File

@ -30,7 +30,7 @@ export class BisqDashboardComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.seoService.setTitle($localize`:@@meta.title.bisq.markets:Markets`); this.seoService.setTitle($localize`:@@meta.title.bisq.markets:Markets`);
this.seoService.setDescription($localize`:@@meta.description.bisq.markets:Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Bisq market prices, trading activity, and more.`); this.seoService.setDescription($localize`:@@meta.description.bisq.markets:Explore the full Bitcoin ecosystem with The Mempool Open Source Project™. See Bisq market prices, trading activity, and more.`);
this.websocketService.want(['blocks']); this.websocketService.want(['blocks']);
this.volumes$ = this.bisqApiService.getAllVolumesDay$() this.volumes$ = this.bisqApiService.getAllVolumesDay$()

View File

@ -36,14 +36,14 @@
<div id="become-sponsor-container"> <div id="become-sponsor-container">
<div class="become-sponsor community"> <div class="become-sponsor community">
<p style="font-weight: 700; font-size: 18px;">If you're an individual...</p> <p style="font-weight: 700; font-size: 18px;">If you're an individual...</p>
<a href="https://mempool.space/sponsor" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.community-sponsor-button">Become a Community Sponsor</a> <a href="https://mempool.space/sponsor" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.community-sponsor-button" (click)="onSponsorClick($event)">Become a Community Sponsor</a>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Exclusive swag</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Exclusive swag</p>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Your avatar on the About page</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Your avatar on the About page</p>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> And more coming soon :)</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> And more coming soon :)</p>
</div> </div>
<div class="become-sponsor enterprise"> <div class="become-sponsor enterprise">
<p style="font-weight: 700; font-size: 18px;">If you're a business...</p> <p style="font-weight: 700; font-size: 18px;">If you're a business...</p>
<a href="https://mempool.space/enterprise" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.enterprise-sponsor-button">Become an Enterprise Sponsor</a> <a href="https://mempool.space/enterprise" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.enterprise-sponsor-button" (click)="onEnterpriseClick($event)">Become an Enterprise Sponsor</a>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Increased API limits</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Increased API limits</p>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Co-branded instance</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> Co-branded instance</p>
<p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> 99% service-level agreement</p> <p class="sponsor-feature"><fa-icon [icon]="['fas', 'check']"></fa-icon> 99% service-level agreement</p>

View File

@ -282,6 +282,7 @@
text-align: left; text-align: left;
width: 250px; width: 250px;
margin: 12px auto; margin: 12px auto;
white-space: nowrap;
} }
@media (max-width: 992px) { @media (max-width: 992px) {

View File

@ -9,6 +9,7 @@ import { Router, ActivatedRoute } from '@angular/router';
import { map, share, tap } from 'rxjs/operators'; import { map, share, tap } from 'rxjs/operators';
import { ITranslators } from '../../interfaces/node-api.interface'; import { ITranslators } from '../../interfaces/node-api.interface';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { EnterpriseService } from '../../services/enterprise.service';
@Component({ @Component({
selector: 'app-about', selector: 'app-about',
@ -33,6 +34,7 @@ export class AboutComponent implements OnInit {
private websocketService: WebsocketService, private websocketService: WebsocketService,
private seoService: SeoService, private seoService: SeoService,
public stateService: StateService, public stateService: StateService,
private enterpriseService: EnterpriseService,
private apiService: ApiService, private apiService: ApiService,
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
@ -108,4 +110,14 @@ export class AboutComponent implements OnInit {
unmutePromoVideo(): void { unmutePromoVideo(): void {
this.promoVideo.nativeElement.muted = false; this.promoVideo.nativeElement.muted = false;
} }
onSponsorClick(e): boolean {
this.enterpriseService.goal(5);
return true;
}
onEnterpriseClick(e): boolean {
this.enterpriseService.goal(6);
return true;
}
} }

View File

@ -51,7 +51,7 @@
In-band fees In-band fees
</td> </td>
<td style="text-align: end;"> <td style="text-align: end;">
{{ estimate.txSummary.effectiveFee | number : '1.0-0' }} <span class="symbol" i18n="shared.sats|sats">sats</span> {{ estimate.txSummary.effectiveFee | number : '1.0-0' }} <span class="symbol" i18n="shared.sats">sats</span>
</td> </td>
</tr> </tr>
<tr class="info group-last"> <tr class="info group-last">
@ -76,7 +76,7 @@
<div class="d-flex mb-0"> <div class="d-flex mb-0">
<ng-container *ngFor="let option of maxRateOptions"> <ng-container *ngFor="let option of maxRateOptions">
<button type="button" class="btn btn-primary flex-grow-1 btn-border btn-sm feerate" [class]="{active: selectFeeRateIndex === option.index}" (click)="setUserBid(option)"> <button type="button" class="btn btn-primary flex-grow-1 btn-border btn-sm feerate" [class]="{active: selectFeeRateIndex === option.index}" (click)="setUserBid(option)">
<span class="fee">{{ option.fee + estimate.mempoolBaseFee + estimate.vsizeFee | number }} <span class="symbol" i18n="shared.sats|sats">sats</span></span> <span class="fee">{{ option.fee + estimate.mempoolBaseFee + estimate.vsizeFee | number }} <span class="symbol" i18n="shared.sats">sats</span></span>
<span class="rate">~<app-fee-rate [fee]="option.rate" rounding="1.0-0"></app-fee-rate></span> <span class="rate">~<app-fee-rate [fee]="option.rate" rounding="1.0-0"></app-fee-rate></span>
</button> </button>
</ng-container> </ng-container>
@ -110,7 +110,7 @@
{{ math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee) | number }} {{ math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee) | number }}
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"><app-fiat [value]="math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee)"></app-fiat></span> <span class="fiat ml-1"><app-fiat [value]="math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee)"></app-fiat></span>
</td> </td>
</tr> </tr>
@ -130,7 +130,7 @@
+{{ estimate.mempoolBaseFee | number }} +{{ estimate.mempoolBaseFee | number }}
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"><app-fiat [value]="estimate.mempoolBaseFee"></app-fiat></span> <span class="fiat ml-1"><app-fiat [value]="estimate.mempoolBaseFee"></app-fiat></span>
</td> </td>
</tr> </tr>
@ -142,7 +142,7 @@
+{{ estimate.vsizeFee | number }} +{{ estimate.vsizeFee | number }}
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"><app-fiat [value]="estimate.vsizeFee"></app-fiat></span> <span class="fiat ml-1"><app-fiat [value]="estimate.vsizeFee"></app-fiat></span>
</td> </td>
</tr> </tr>
@ -159,7 +159,7 @@
</span> </span>
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"><app-fiat [value]="estimate.cost + estimate.mempoolBaseFee + estimate.vsizeFee"></app-fiat></span> <span class="fiat ml-1"><app-fiat [value]="estimate.cost + estimate.mempoolBaseFee + estimate.vsizeFee"></app-fiat></span>
</td> </td>
</tr> </tr>
@ -182,7 +182,7 @@
</span> </span>
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"> <span class="fiat ml-1">
<app-fiat [value]="maxCost" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat> <app-fiat [value]="maxCost" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat>
</span> </span>
@ -205,7 +205,7 @@
{{ estimate.userBalance | number }} {{ estimate.userBalance | number }}
</td> </td>
<td class="units"> <td class="units">
<span class="symbol" i18n="shared.sats|sats">sats</span> <span class="symbol" i18n="shared.sats">sats</span>
<span class="fiat ml-1"> <span class="fiat ml-1">
<app-fiat [value]="estimate.userBalance" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat> <app-fiat [value]="estimate.userBalance" [colorClass]="estimate.userBalance < maxCost ? 'red-color' : 'green-color'"></app-fiat>
</span> </span>

View File

@ -219,13 +219,13 @@
<div class="box" *ngIf="!error && webGlEnabled && showAudit"> <div class="box" *ngIf="!error && webGlEnabled && showAudit">
<div class="nav nav-tabs" *ngIf="isMobile && showAudit"> <div class="nav nav-tabs" *ngIf="isMobile && showAudit">
<a class="nav-link" [class.active]="mode === 'projected'" <a class="nav-link" [class.active]="mode === 'projected'"
fragment="projected" (click)="changeMode('projected')"><ng-container i18n="block.expected">Expected</ng-container>&nbsp;&nbsp;<span class="badge badge-pill badge-warning" i18n="beta">beta</span></a> fragment="projected" (click)="changeMode('projected')"><ng-container i18n="block.expected">Expected</ng-container></a>
<a class="nav-link" [class.active]="mode === 'actual'" i18n="block.actual" <a class="nav-link" [class.active]="mode === 'actual'" i18n="block.actual"
fragment="actual" (click)="changeMode('actual')">Actual</a> fragment="actual" (click)="changeMode('actual')">Actual</a>
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm"> <div class="col-sm">
<h3 class="block-subtitle" *ngIf="!isMobile"><ng-container i18n="block.expected-block">Expected Block</ng-container> <span class="badge badge-pill badge-warning beta" i18n="beta">beta</span></h3> <h3 class="block-subtitle" *ngIf="!isMobile"><ng-container i18n="block.expected-block">Expected Block</ng-container></h3>
<div class="block-graph-wrapper"> <div class="block-graph-wrapper">
<app-block-overview-graph #blockGraphProjected [isLoading]="isLoadingOverview" [resolution]="86" <app-block-overview-graph #blockGraphProjected [isLoading]="isLoadingOverview" [resolution]="86"
[blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" [auditHighlighting]="showAudit" [blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" [auditHighlighting]="showAudit"
@ -262,7 +262,7 @@
<tbody> <tbody>
<tr> <tr>
<td class="td-width" i18n="transaction.version">Version</td> <td class="td-width" i18n="transaction.version">Version</td>
<td>{{ block.version | decimal2hex }} <span *ngIf="displayTaprootStatus() && hasTaproot(block.version)" class="badge badge-success ml-1" >Taproot</span></td> <td>{{ block.version | decimal2hex }} <span *ngIf="displayTaprootStatus() && hasTaproot(block.version)" class="badge badge-success ml-1" i18n="tx-features.tag.taproot|Taproot">Taproot</span></td>
</tr> </tr>
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'"> <tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<td i18n="block.bits">Bits</td> <td i18n="block.bits">Bits</td>

View File

@ -55,7 +55,9 @@ export class BlocksList implements OnInit {
this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5;
this.seoService.setTitle($localize`:@@meta.title.blocks-list:Blocks`); if (!this.widget) {
this.seoService.setTitle($localize`:@@m8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`);
}
if( this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet' ) { if( this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet' ) {
this.seoService.setDescription($localize`:@@meta.description.liquid.blocks:See the most recent Liquid${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block size, and more.`); this.seoService.setDescription($localize`:@@meta.description.liquid.blocks:See the most recent Liquid${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block size, and more.`);
} else { } else {

View File

@ -1,6 +1,6 @@
<div class="container-xl"> <div class="container-xl">
<div class="text-center"> <div class="text-center">
<h2>Calculator</h2> <h2 i18n="shared.calculator">Calculator</h2>
</div> </div>
<ng-container *ngIf="price$ | async; else loading"> <ng-container *ngIf="price$ | async; else loading">
@ -26,7 +26,7 @@
<div class="input-group input-group-lg mb-1"> <div class="input-group input-group-lg mb-1">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">sats</span> <span class="input-group-text" i18n="shared.sats">sats</span>
</div> </div>
<input type="text" class="form-control" formControlName="satoshis" (input)="transformInput('satoshis')" (click)="selectAll($event)"> <input type="text" class="form-control" formControlName="satoshis" (input)="transformInput('satoshis')" (click)="selectAll($event)">
<app-clipboard [button]="true" [text]="form.get('satoshis').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard> <app-clipboard [button]="true" [text]="form.get('satoshis').value" [class]="'btn btn-lg btn-secondary ml-1'"></app-clipboard>
@ -41,7 +41,7 @@
<div class="bitcoin-satoshis-text"> <div class="bitcoin-satoshis-text">
<span [innerHTML]="form.get('bitcoin').value | bitcoinsatoshis"></span> <span [innerHTML]="form.get('bitcoin').value | bitcoinsatoshis"></span>
<span class="sats"> sats</span> <span class="sats" i18n="shared.sats">sats</span>
</div> </div>
</div> </div>

View File

@ -38,36 +38,35 @@
</div> </div>
<ng-container *ngIf="!hideStats"> <ng-container *ngIf="!hideStats">
<div class="stats top left"> <div class="stats top left">
<p class="label" i18n="clock.fiat-price">fiat price</p> <p class="label" i18n>Price</p>
<p> <p>
<app-fiat [value]="100000000" digitsInfo="1.2-2" colorClass="white-color"></app-fiat> <app-fiat [value]="100000000" digitsInfo="1.2-2" colorClass="white-color"></app-fiat>
</p> </p>
</div> </div>
<div class="stats top right"> <div class="stats top right">
<p class="label" i18n="clock.priority-rate|priority fee rate">priority rate</p> <p class="label" i18n="fees-box.high-priority">High Priority</p>
<p *ngIf="recommendedFees$ | async as recommendedFees;"> <p *ngIf="recommendedFees$ | async as recommendedFees;">
<app-fee-rate [fee]="recommendedFees.fastestFee" unitClass="" rounding="1.0-0"></app-fee-rate> <app-fee-rate [fee]="recommendedFees.fastestFee" unitClass="" rounding="1.0-0"></app-fee-rate>
</p> </p>
</div> </div>
<div *ngIf="mode !== 'mempool' && blocks?.length" class="stats bottom left"> <div *ngIf="mode !== 'mempool' && blocks?.length" class="stats bottom left">
<p [innerHTML]="blocks[blockIndex].size | bytes: 2"></p> <p [innerHTML]="blocks[blockIndex].size | bytes: 2"></p>
<p class="label" i18n="clock.block-size">block size</p> <p class="label" i18n="block.size">Size</p>
</div> </div>
<div *ngIf="mode !== 'mempool' && blocks?.length" class="stats bottom right"> <div *ngIf="mode !== 'mempool' && blocks?.length" class="stats bottom right">
<p class="force-wrap"> <p class="force-wrap">
<ng-container *ngTemplateOutlet="blocks[blockIndex].tx_count === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: blocks[blockIndex].tx_count | number}"></ng-container> {{ blocks[blockIndex].tx_count | number }}
<ng-template #transactionsSingular let-i i18n="shared.transaction-count.singular">{{ i }} <span class="label">transaction</span></ng-template> <span class="label" i18n="dashboard.txs">Transactions</span>
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} <span class="label">transactions</span></ng-template>
</p> </p>
</div> </div>
<ng-container *ngIf="mempoolInfo$ | async as mempoolInfo;"> <ng-container *ngIf="mempoolInfo$ | async as mempoolInfo;">
<div *ngIf="mode === 'mempool'" class="stats bottom left"> <div *ngIf="mode === 'mempool'" class="stats bottom left">
<p [innerHTML]="mempoolInfo.usage | bytes: 0"></p> <p [innerHTML]="mempoolInfo.usage | bytes: 0"></p>
<p class="label" i18n="dashboard.memory-usage|Memory usage">memory usage</p> <p class="label" i18n="dashboard.memory-usage|Memory usage">Memory Usage</p>
</div> </div>
<div *ngIf="mode === 'mempool'" class="stats bottom right"> <div *ngIf="mode === 'mempool'" class="stats bottom right">
<p>{{ mempoolInfo.size | number }}</p> <p>{{ mempoolInfo.size | number }}</p>
<p class="label" i18n="dashboard.unconfirmed|Unconfirmed count">unconfirmed</p> <p class="label" i18n="dashboard.unconfirmed|Unconfirmed count">Unconfirmed</p>
</div> </div>
</ng-container> </ng-container>
</ng-container> </ng-container>

View File

@ -63,6 +63,7 @@
.label { .label {
font-size: calc(0.04 * var(--clock-width)); font-size: calc(0.04 * var(--clock-width));
line-height: calc(0.05 * var(--clock-width)); line-height: calc(0.05 * var(--clock-width));
text-transform: lowercase;
} }
&.top { &.top {

View File

@ -11,7 +11,7 @@
<div class="progress inc-tx-progress-bar"> <div class="progress inc-tx-progress-bar">
<div class="progress-bar" role="progressbar" [ngStyle]="{'width': mempoolInfoData.progressWidth, 'background-color': mempoolInfoData.progressColor}">&nbsp;</div> <div class="progress-bar" role="progressbar" [ngStyle]="{'width': mempoolInfoData.progressWidth, 'background-color': mempoolInfoData.progressColor}">&nbsp;</div>
<div class="progress-text" *only-vsize>&lrm;{{ mempoolInfoData.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div> <div class="progress-text" *only-vsize>&lrm;{{ mempoolInfoData.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div>
<div class="progress-text" *only-weight>&lrm;{{ mempoolInfoData.vBytesPerSecond * 4 | ceil | number }} <ng-container i18n="shared.weight-units-per-second|vB/s">WU/s</ng-container></div> <div class="progress-text" *only-weight>&lrm;{{ mempoolInfoData.vBytesPerSecond * 4 | ceil | number }} <ng-container i18n="shared.weight-per-second|WU/s">WU/s</ng-container></div>
</div> </div>
</ng-template> </ng-template>
</ng-template> </ng-template>

View File

@ -22,7 +22,7 @@
<a class="dropdown-item" routerLinkActive="active" <a class="dropdown-item" routerLinkActive="active"
[routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]" i18n="mining.block-sizes-weights">Block Sizes and Weights</a> [routerLink]="['/graphs/mining/block-sizes-weights' | relativeUrl]" i18n="mining.block-sizes-weights">Block Sizes and Weights</a>
<a *ngIf="stateService.env.AUDIT" class="dropdown-item" routerLinkActive="active" <a *ngIf="stateService.env.AUDIT" class="dropdown-item" routerLinkActive="active"
[routerLink]="['/graphs/mining/block-health' | relativeUrl]" i18n="mining.block-health">Block Health</a> [routerLink]="['/graphs/mining/block-health' | relativeUrl]" i18n="mining.blocks-health">Block Health</a>
</div> </div>
</div> </div>

View File

@ -249,10 +249,8 @@ export class HashrateChartComponent implements OnInit {
for (const tick of ticks) { for (const tick of ticks) {
if (tick.seriesIndex === 0) { // Hashrate if (tick.seriesIndex === 0) { // Hashrate
let hashrate = tick.data[1]; let hashrate = tick.data[1];
if (this.isMobile()) { hashratePowerOfTen = selectPowerOfTen(tick.data[1]);
hashratePowerOfTen = selectPowerOfTen(tick.data[1]); hashrate = Math.round(tick.data[1] / hashratePowerOfTen.divider);
hashrate = Math.round(tick.data[1] / hashratePowerOfTen.divider);
}
hashrateString = `${tick.marker} ${tick.seriesName}: ${formatNumber(hashrate, this.locale, '1.0-0')} ${hashratePowerOfTen.unit}H/s<br>`; hashrateString = `${tick.marker} ${tick.seriesName}: ${formatNumber(hashrate, this.locale, '1.0-0')} ${hashratePowerOfTen.unit}H/s<br>`;
} else if (tick.seriesIndex === 1) { // Difficulty } else if (tick.seriesIndex === 1) { // Difficulty
let difficultyPowerOfTen = hashratePowerOfTen; let difficultyPowerOfTen = hashratePowerOfTen;
@ -260,18 +258,14 @@ export class HashrateChartComponent implements OnInit {
if (difficulty === null) { if (difficulty === null) {
difficultyString = `${tick.marker} ${tick.seriesName}: No data<br>`; difficultyString = `${tick.marker} ${tick.seriesName}: No data<br>`;
} else { } else {
if (this.isMobile()) { difficultyPowerOfTen = selectPowerOfTen(tick.data[1]);
difficultyPowerOfTen = selectPowerOfTen(tick.data[1]); difficulty = tick.data[1] / difficultyPowerOfTen.divider;
difficulty = Math.round(tick.data[1] / difficultyPowerOfTen.divider);
}
difficultyString = `${tick.marker} ${tick.seriesName}: ${formatNumber(difficulty, this.locale, '1.2-2')} ${difficultyPowerOfTen.unit}<br>`; difficultyString = `${tick.marker} ${tick.seriesName}: ${formatNumber(difficulty, this.locale, '1.2-2')} ${difficultyPowerOfTen.unit}<br>`;
} }
} else if (tick.seriesIndex === 2) { // Hashrate MA } else if (tick.seriesIndex === 2) { // Hashrate MA
let hashrate = tick.data[1]; let hashrate = tick.data[1];
if (this.isMobile()) { hashratePowerOfTen = selectPowerOfTen(tick.data[1]);
hashratePowerOfTen = selectPowerOfTen(tick.data[1]); hashrate = Math.round(tick.data[1] / hashratePowerOfTen.divider);
hashrate = Math.round(tick.data[1] / hashratePowerOfTen.divider);
}
hashrateStringMA = `${tick.marker} ${tick.seriesName}: ${formatNumber(hashrate, this.locale, '1.0-0')} ${hashratePowerOfTen.unit}H/s`; hashrateStringMA = `${tick.marker} ${tick.seriesName}: ${formatNumber(hashrate, this.locale, '1.0-0')} ${hashratePowerOfTen.unit}H/s`;
} }
} }

View File

@ -7,7 +7,7 @@
</span> </span>
<a *ngIf="!userAuth" class="d-flex justify-content-center align-items-center nav-link m-0 menu-click" routerLink="/login" role="tab" (click)="onLinkClick('/login')"> <a *ngIf="!userAuth" class="d-flex justify-content-center align-items-center nav-link m-0 menu-click" routerLink="/login" role="tab" (click)="onLinkClick('/login')">
<fa-icon class="menu-click" [icon]="['fas', 'user-circle']" [fixedWidth]="true" style="font-size: 25px;margin-right: 15px;"></fa-icon> <fa-icon class="menu-click" [icon]="['fas', 'user-circle']" [fixedWidth]="true" style="font-size: 25px;margin-right: 15px;"></fa-icon>
<span class="menu-click" style="font-size: 20px;">Sign in</span> <span class="menu-click" style="font-size: 20px;" i18n="shared.sign-in">Sign in</span>
</a> </a>
<ng-container *ngIf="userMenuGroups$ | async as menuGroups"> <ng-container *ngIf="userMenuGroups$ | async as menuGroups">

View File

@ -44,12 +44,12 @@
</div> </div>
</div> </div>
<!-- Latest blocks --> <!-- Recent blocks -->
<div class="col"> <div class="col">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]"> <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]">
<h5 class="card-title d-inline" i18n="dashboard.latest-blocks">Latest blocks</h5> <h5 class="card-title d-inline" i18n="dashboard.recent-blocks">Recent Blocks</h5>
<span>&nbsp;</span> <span>&nbsp;</span>
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon>
</a> </a>

View File

@ -6,7 +6,7 @@
<div class="pool-distribution" *ngIf="(miningStatsObservable$ | async) as miningStats; else loadingReward"> <div class="pool-distribution" *ngIf="(miningStatsObservable$ | async) as miningStats; else loadingReward">
<div class="item"> <div class="item">
<h5 class="card-title d-inline-block" i18n="mining.miners-luck" i18n-ngbTooltip="mining.miners-luck-1w" <h5 class="card-title d-inline-block" i18n="mining.miners-luck" i18n-ngbTooltip="mining.miners-luck-1w"
ngbTooltip="Pools luck (1 week)" placement="bottom" #minersluck [disableTooltip]="!isEllipsisActive(minersluck)">Pools luck</h5> ngbTooltip="Pools luck (1 week)" placement="bottom" #minersluck [disableTooltip]="!isEllipsisActive(minersluck)">Pools Luck</h5>
<p class="card-text" i18n-ngbTooltip="mining.pools-luck-desc" <p class="card-text" i18n-ngbTooltip="mining.pools-luck-desc"
ngbTooltip="The overall luck of all mining pools over the past week. A luck bigger than 100% means the average block time for the current epoch is less than 10 minutes." placement="bottom"> ngbTooltip="The overall luck of all mining pools over the past week. A luck bigger than 100% means the average block time for the current epoch is less than 10 minutes." placement="bottom">
{{ miningStats['minersLuck'] }}% {{ miningStats['minersLuck'] }}%
@ -14,14 +14,14 @@
</div> </div>
<div class="item"> <div class="item">
<h5 class="card-title d-inline-block" i18n="mining.miners-count" i18n-ngbTooltip="mining.miners-count-1w" <h5 class="card-title d-inline-block" i18n="mining.miners-count" i18n-ngbTooltip="mining.miners-count-1w"
ngbTooltip="Pools count (1w)" placement="bottom" #poolscount [disableTooltip]="!isEllipsisActive(poolscount)">Pools count</h5> ngbTooltip="Pools count (1w)" placement="bottom" #poolscount [disableTooltip]="!isEllipsisActive(poolscount)">Pools Count</h5>
<p class="card-text" i18n-ngbTooltip="mining.pools-count-desc" <p class="card-text" i18n-ngbTooltip="mining.pools-count-desc"
ngbTooltip="How many unique pools found at least one block over the past week." placement="bottom"> ngbTooltip="How many unique pools found at least one block over the past week." placement="bottom">
{{ miningStats.pools.length }} {{ miningStats.pools.length }}
</p> </p>
</div> </div>
<div class="item"> <div class="item">
<h5 class="card-title d-inline-block" i18n="master-page.blocks" i18n-ngbTooltip="master-page.blocks" <h5 class="card-title d-inline-block" i18n="shared.blocks-1w" i18n-ngbTooltip="master-page.blocks"
ngbTooltip="Blocks (1w)" placement="bottom" #blockscount [disableTooltip]="!isEllipsisActive(blockscount)">Blocks (1w)</h5> ngbTooltip="Blocks (1w)" placement="bottom" #blockscount [disableTooltip]="!isEllipsisActive(blockscount)">Blocks (1w)</h5>
<p class="card-text" i18n-ngbTooltip="mining.blocks-count-desc" <p class="card-text" i18n-ngbTooltip="mining.blocks-count-desc"
ngbTooltip="The number of blocks found over the past week." placement="bottom"> ngbTooltip="The number of blocks found over the past week." placement="bottom">
@ -95,7 +95,7 @@
<th *ngIf="auditAvailable" class="health text-right widget" i18n="latest-blocks.avg_health" <th *ngIf="auditAvailable" class="health text-right widget" i18n="latest-blocks.avg_health"
i18n-ngbTooltip="latest-blocks.avg_health" ngbTooltip="Avg Health" placement="bottom" #health [disableTooltip]="!isEllipsisActive(health)">Avg Health</th> i18n-ngbTooltip="latest-blocks.avg_health" ngbTooltip="Avg Health" placement="bottom" #health [disableTooltip]="!isEllipsisActive(health)">Avg Health</th>
<th *ngIf="auditAvailable" class="d-none d-sm-table-cell" i18n="mining.fees-per-block">Avg Block Fees</th> <th *ngIf="auditAvailable" class="d-none d-sm-table-cell" i18n="mining.fees-per-block">Avg Block Fees</th>
<th class="d-none d-lg-table-cell" i18n="mining.empty-blocks">Empty blocks</th> <th class="d-none d-lg-table-cell" i18n="mining.empty-blocks">Empty Blocks</th>
</tr> </tr>
</thead> </thead>
<tbody [attr.data-cy]="'pools-table'" *ngIf="(miningStatsObservable$ | async) as miningStats"> <tbody [attr.data-cy]="'pools-table'" *ngIf="(miningStatsObservable$ | async) as miningStats">
@ -153,19 +153,19 @@
<ng-template #loadingReward> <ng-template #loadingReward>
<div class="pool-distribution"> <div class="pool-distribution">
<div class="item"> <div class="item">
<h5 class="card-title" i18n="mining.miners-luck">Pools Luck (1w)</h5> <h5 class="card-title" i18n="mining.miners-luck">Pools Luck</h5>
<p class="card-text"> <p class="card-text">
<span class="skeleton-loader skeleton-loader-big"></span> <span class="skeleton-loader skeleton-loader-big"></span>
</p> </p>
</div> </div>
<div class="item"> <div class="item">
<h5 class="card-title" i18n="master-page.blocks">Blocks (1w)</h5> <h5 class="card-title" i18n="mining.miners-count" >Pools Count</h5>
<p class="card-text"> <p class="card-text">
<span class="skeleton-loader skeleton-loader-big"></span> <span class="skeleton-loader skeleton-loader-big"></span>
</p> </p>
</div> </div>
<div class="item"> <div class="item">
<h5 class="card-title" i18n="mining.miners-count">Pools Count (1w)</h5> <h5 class="card-title" i18n="shared.blocks-1w">Blocks (1w)</h5>
<p class="card-text"> <p class="card-text">
<span class="skeleton-loader skeleton-loader-big"></span> <span class="skeleton-loader skeleton-loader-big"></span>
</p> </p>

View File

@ -143,7 +143,7 @@
<table class="table table-xs table-data"> <table class="table table-xs table-data">
<thead> <thead>
<tr> <tr>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks 24h</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks (24h)</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th>
</tr> </tr>
@ -165,7 +165,7 @@
<table class="table table-xs table-data"> <table class="table table-xs table-data">
<thead> <thead>
<tr> <tr>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks 24h</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks (24h)</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th>
</tr> </tr>
@ -433,7 +433,7 @@
<table class="table table-xs table-data text-center"> <table class="table table-xs table-data text-center">
<thead> <thead>
<tr> <tr>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks 24h</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks (24h)</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th>
</tr> </tr>
@ -458,7 +458,7 @@
<table class="table table-xs table-data text-center"> <table class="table table-xs table-data text-center">
<thead> <thead>
<tr> <tr>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks 24h</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="24h">Blocks (24h)</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="1w">1w</th>
<th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th> <th scope="col" class="data-title text-center" style="width: 33%" i18n="all">All</th>
</tr> </tr>

View File

@ -6,11 +6,9 @@
<form class="formRadioGroup"> <form class="formRadioGroup">
<div class="btn-group btn-group-toggle" name="radioBasic"> <div class="btn-group btn-group-toggle" name="radioBasic">
<label class="btn btn-primary btn-sm" [class.active]="!fullRbf"> <label class="btn btn-primary btn-sm" [class.active]="!fullRbf">
<input type="radio" [value]="'All'" fragment="" [routerLink]="[]"> All <input type="radio" [value]="'All'" fragment="" [routerLink]="[]"><span i18n="all">All</span></label>
</label>
<label class="btn btn-primary btn-sm" [class.active]="fullRbf"> <label class="btn btn-primary btn-sm" [class.active]="fullRbf">
<input type="radio" [value]="'Full RBF'" fragment="fullrbf" [routerLink]="[]"> Full RBF <input type="radio" [value]="'Full RBF'" fragment="fullrbf" [routerLink]="[]" i18n="transaction.full-rbf">Full RBF</label>
</label>
</div> </div>
</form> </form>
</div> </div>
@ -33,7 +31,7 @@
</div> </div>
<div class="no-replacements" *ngIf="!trees?.length"> <div class="no-replacements" *ngIf="!trees?.length">
<p i18n="rbf.no-replacements-yet">there are no replacements in the mempool yet!</p> <p i18n="rbf.no-replacements-yet">There are no replacements in the mempool yet!</p>
</div> </div>
</ng-container> </ng-container>
</div> </div>

View File

@ -55,7 +55,7 @@ export class RbfList implements OnInit, OnDestroy {
}) })
); );
this.seoService.setTitle($localize`:@@meta.title.rbf-list:RBF Replacements`); this.seoService.setTitle($localize`:@@5e3d5a82750902f159122fcca487b07f1af3141f:RBF Replacements`);
this.seoService.setDescription($localize`:@@meta.description.rbf-list:See the most recent RBF replacements on the Bitcoin${seoDescriptionNetwork(this.stateService.network)} network, updated in real-time.`); this.seoService.setDescription($localize`:@@meta.description.rbf-list:See the most recent RBF replacements on the Bitcoin${seoDescriptionNetwork(this.stateService.network)} network, updated in real-time.`);
} }

View File

@ -32,9 +32,9 @@
<tr> <tr>
<td class="td-width" i18n="transaction.status|Transaction Status">Status</td> <td class="td-width" i18n="transaction.status|Transaction Status">Status</td>
<td> <td>
<span *ngIf="rbfInfo.tx.fullRbf" class="badge badge-info" i18n="rbfInfo-features.tag.full-rbf|Full RBF">Full RBF</span> <span *ngIf="rbfInfo.tx.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span>
<span *ngIf="rbfInfo.tx.rbf; else rbfDisabled" class="badge badge-success" i18n="rbfInfo-features.tag.rbf|RBF">RBF</span> <span *ngIf="rbfInfo.tx.rbf; else rbfDisabled" class="badge badge-success" i18n="rbfInfo-features.tag.rbf|RBF">RBF</span>
<ng-template #rbfDisabled><span class="badge badge-danger mr-1"><del i18n="rbfInfo-features.tag.rbf|RBF">RBF</del></span></ng-template> <ng-template #rbfDisabled><span class="badge badge-danger mr-1"><del i18n="tx-features.tag.rbf|RBF">RBF</del></span></ng-template>
<span *ngIf="rbfInfo.tx.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span> <span *ngIf="rbfInfo.tx.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span>
</td> </td>
</tr> </tr>

View File

@ -14,7 +14,7 @@
[class]="(stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING) ? 'mining' : 'no-menu'" (click)="saveGraphPreference()"> [class]="(stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING) ? 'mining' : 'no-menu'" (click)="saveGraphPreference()">
<div class="small-buttons"> <div class="small-buttons">
<a class="btn btn-primary btn-sm mb-0" [routerLink]="['/clock/mempool/0' | relativeUrl]" style="color: white" id="btn-clock"> <a class="btn btn-primary btn-sm mb-0" [routerLink]="['/clock/mempool/0' | relativeUrl]" style="color: white" id="btn-clock">
<fa-icon [icon]="['fas', 'clock']" [fixedWidth]="true" i18n-title="master-page.clockview" title="Clock view"></fa-icon> <fa-icon [icon]="['fas', 'clock']" [fixedWidth]="true" i18n-title="master-page.clockview" i18n-title="footer.clock-mempool" title="Clock (Mempool)"></fa-icon>
</a> </a>
<a *ngIf="!isMobile()" class="btn btn-primary btn-sm mb-0" [routerLink]="['/tv' | relativeUrl]" style="color: white" id="btn-tv"> <a *ngIf="!isMobile()" class="btn btn-primary btn-sm mb-0" [routerLink]="['/tv' | relativeUrl]" style="color: white" id="btn-tv">
<fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon> <fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon>

View File

@ -40,7 +40,7 @@
<ng-container [ngSwitch]="extraData"> <ng-container [ngSwitch]="extraData">
<div class="opreturns" *ngSwitchCase="'coinbase'"> <div class="opreturns" *ngSwitchCase="'coinbase'">
<div class="opreturn-row"> <div class="opreturn-row">
<span class="label">Coinbase</span> <span class="label" i18n="transactions-list.coinbase">Coinbase</span>
<span class="message">{{ tx.vin[0].scriptsig | hex2ascii }}</span> <span class="message">{{ tx.vin[0].scriptsig | hex2ascii }}</span>
</div> </div>
</div> </div>

View File

@ -519,7 +519,7 @@
<div class="effective-fee-container"> <div class="effective-fee-container">
<app-fee-rate [fee]="tx.effectiveFeePerVsize"></app-fee-rate> <app-fee-rate [fee]="tx.effectiveFeePerVsize"></app-fee-rate>
<ng-template [ngIf]="tx?.status?.confirmed"> <ng-template [ngIf]="tx?.status?.confirmed">
<app-tx-fee-rating class="ml-2 mr-2" *ngIf="tx.fee || tx.effectiveFeePerVsize" [tx]="tx"></app-tx-fee-rating> <app-tx-fee-rating class="ml-2 mr-2 effective-fee-rating" *ngIf="tx.fee || tx.effectiveFeePerVsize" [tx]="tx"></app-tx-fee-rating>
</ng-template> </ng-template>
</div> </div>
<button *ngIf="cpfpInfo.bestDescendant || cpfpInfo.descendants?.length || cpfpInfo.ancestors?.length" type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button> <button *ngIf="cpfpInfo.bestDescendant || cpfpInfo.descendants?.length || cpfpInfo.ancestors?.length" type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button>

View File

@ -152,6 +152,16 @@
@media (min-width: 768px){ @media (min-width: 768px){
display: inline-block; display: inline-block;
} }
@media (max-width: 425px){
display: flex;
flex-direction: column;
}
}
.effective-fee-rating {
@media (max-width: 767px){
margin-right: 0px !important;
}
} }
.title { .title {

View File

@ -16,7 +16,7 @@
<ng-template #coinbase> <ng-template #coinbase>
<ng-container *ngIf="line.coinbase; else pegin"> <ng-container *ngIf="line.coinbase; else pegin">
<p>Coinbase</p> <p i18n="transactions-list.coinbase">Coinbase</p>
</ng-container> </ng-container>
</ng-template> </ng-template>

View File

@ -76,7 +76,7 @@
<div class="card" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else latestBlocks"> <div class="card" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else latestBlocks">
<div class="card-body"> <div class="card-body">
<a class="title-link" href="" [routerLink]="['/rbf' | relativeUrl]"> <a class="title-link" href="" [routerLink]="['/rbf' | relativeUrl]">
<h5 class="card-title d-inline" i18n="dashboard.latest-rbf-replacements">Latest replacements</h5> <h5 class="card-title d-inline" i18n="dashboard.recent-rbf-replacements">Recent Replacements</h5>
<span>&nbsp;</span> <span>&nbsp;</span>
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon>
</a> </a>
@ -99,7 +99,7 @@
<td class="table-cell-badges"> <td class="table-cell-badges">
<span *ngIf="replacement.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span> <span *ngIf="replacement.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span>
<span *ngIf="replacement.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span> <span *ngIf="replacement.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span>
<span *ngIf="!replacement.fullRbf" class="badge badge-success" i18n="transaction.rbf">RBF</span> <span *ngIf="!replacement.fullRbf" class="badge badge-success" i18n="tx-features.tag.rbf|RBF">RBF</span>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -110,7 +110,7 @@
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]"> <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]">
<h5 class="card-title d-inline" i18n="dashboard.latest-blocks">Latest blocks</h5> <h5 class="card-title d-inline" i18n="dashboard.recent-blocks">Recent Blocks</h5>
<span>&nbsp;</span> <span>&nbsp;</span>
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: #4a68b9"></fa-icon>
</a> </a>
@ -150,7 +150,7 @@
<div class="col" style="max-height: 410px"> <div class="col" style="max-height: 410px">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title" i18n="dashboard.latest-transactions">Latest transactions</h5> <h5 class="card-title" i18n="dashboard.recent-transactions">Recent Transactions</h5>
<table class="table latest-transactions"> <table class="table latest-transactions">
<thead> <thead>
<th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th> <th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
@ -233,7 +233,7 @@
</p> </p>
</div> </div>
<div class="item bar"> <div class="item bar">
<h5 class="card-title" i18n="dashboard.memory-usage|Memory usage">Memory usage</h5> <h5 class="card-title" i18n="dashboard.memory-usage|Memory usage">Memory Usage</h5>
<div class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loadingbig"> <div class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loadingbig">
<div class="progress"> <div class="progress">
<div class="progress-bar {{ mempoolInfoData.value.mempoolSizeProgress }}" role="progressbar" [ngStyle]="{'width': (mempoolInfoData.value.memPoolInfo.usage / mempoolInfoData.value.memPoolInfo.maxmempool * 100) + '%' }">&nbsp;</div> <div class="progress-bar {{ mempoolInfoData.value.mempoolSizeProgress }}" role="progressbar" [ngStyle]="{'width': (mempoolInfoData.value.memPoolInfo.usage / mempoolInfoData.value.memPoolInfo.maxmempool * 100) + '%' }">&nbsp;</div>
@ -256,7 +256,7 @@
</ng-template> </ng-template>
<ng-template #txPerSecond let-mempoolInfoData> <ng-template #txPerSecond let-mempoolInfoData>
<h5 class="card-title" i18n="dashboard.incoming-transactions">Incoming transactions</h5> <h5 class="card-title" i18n="dashboard.incoming-transactions">Incoming Transactions</h5>
<ng-template [ngIf]="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value" [ngIfElse]="loadingTransactions"> <ng-template [ngIf]="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value" [ngIfElse]="loadingTransactions">
<span *ngIf="(mempoolLoadingStatus$ | async) !== 100; else inSync"> <span *ngIf="(mempoolLoadingStatus$ | async) !== 100; else inSync">
&nbsp;<span class="badge badge-pill badge-warning"><ng-container i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</ng-container> ({{ mempoolLoadingStatus$ | async }}%)</span> &nbsp;<span class="badge badge-pill badge-warning"><ng-container i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</ng-container> ({{ mempoolLoadingStatus$ | async }}%)</span>

View File

@ -10,9 +10,9 @@
<div class="doc-content"> <div class="doc-content">
<div id="disclaimer"> <div id="disclaimer">
<table *ngIf="!mobileViewport"><tr><td><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images></td><td><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, wallet issues, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table> <table *ngIf="!mobileViewport"><tr><td><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images></td><td> <ng-container *ngTemplateOutlet="faqDisclaimer"></ng-container></td></tr></table>
<div *ngIf="mobileViewport"><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, wallet issues, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></div> <div *ngIf="mobileViewport"><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images><ng-container *ngTemplateOutlet="faqDisclaimer"></ng-container></div>
<ng-template #faqDisclaimer i18n="faq.big-disclaimer"><p><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, wallet issues, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></ng-template>
</div> </div>
<div class="doc-item-container" *ngFor="let item of faq"> <div class="doc-item-container" *ngFor="let item of faq">

View File

@ -64,10 +64,9 @@ export class DocsComponent implements OnInit {
} }
} else { } else {
this.activeTab = 3; this.activeTab = 3;
this.seoService.setTitle($localize`:@@meta.title.docs.websocket:Electrum RPC`); this.seoService.setTitle($localize`:@@meta.title.docs.electrum:Electrum RPC`);
this.seoService.setDescription($localize`:@@meta.description.docs.electrumrpc:Documentation for our Electrum RPC interface: get instant, convenient, and reliable access to an Esplora instance.`); this.seoService.setDescription($localize`:@@meta.description.docs.electrumrpc:Documentation for our Electrum RPC interface: get instant, convenient, and reliable access to an Esplora instance.`);
} }
} }
ngOnDestroy(): void { ngOnDestroy(): void {

View File

@ -37,7 +37,7 @@
<thead> <thead>
<th class="alias text-left" i18n="lightning.alias">Alias</th> <th class="alias text-left" i18n="lightning.alias">Alias</th>
<th class="nodedetails text-left">&nbsp;</th> <th class="nodedetails text-left">&nbsp;</th>
<th class="status text-left" i18n="status">Status</th> <th class="status text-left" i18n="transaction.status|Transaction Status">Status</th>
<th class="feerate text-left" *ngIf="status !== 'closed'" i18n="transaction.fee-rate|Transaction fee rate">Fee rate</th> <th class="feerate text-left" *ngIf="status !== 'closed'" i18n="transaction.fee-rate|Transaction fee rate">Fee rate</th>
<th class="feerate text-left" *ngIf="status === 'closed'" i18n="channels.closing_date">Closing date</th> <th class="feerate text-left" *ngIf="status === 'closed'" i18n="channels.closing_date">Closing date</th>
<th class="liquidity text-right" i18n="lightning.capacity">Capacity</th> <th class="liquidity text-right" i18n="lightning.capacity">Capacity</th>

View File

@ -14,7 +14,7 @@
<table class="table table-borderless table-striped"> <table class="table table-borderless table-striped">
<tbody> <tbody>
<tr> <tr>
<td>Description</td> <td i18n>Description</td>
<td><div class="description-text">These are the Lightning nodes operated by The Mempool Open Source Project that provide data for the mempool.space website. Connect to us! <td><div class="description-text">These are the Lightning nodes operated by The Mempool Open Source Project that provide data for the mempool.space website. Connect to us!
</div> </div>
</td> </td>
@ -70,7 +70,7 @@
<table class="table table-borderless"> <table class="table table-borderless">
<thead> <thead>
<th class="alias text-left" i18n="lightning.alias">Alias</th> <th class="alias text-left" i18n="lightning.alias">Alias</th>
<th class="text-left">Connect</th> <th class="text-left" i18n="lightning.connect-to-node|Connect">Connect</th>
<th class="city text-right d-none d-md-table-cell" i18n="lightning.location">Location</th> <th class="city text-right d-none d-md-table-cell" i18n="lightning.location">Location</th>
</thead> </thead>
<tbody *ngIf="nodes$ | async as response; else skeleton"> <tbody *ngIf="nodes$ | async as response; else skeleton">

View File

@ -49,7 +49,7 @@
<tr *ngIf="!node.city && !node.country"> <tr *ngIf="!node.city && !node.country">
<td i18n="lightning.location">Location</td> <td i18n="lightning.location">Location</td>
<td> <td>
<span>unknown</span> <span i18n="unknown">Unknown</span>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -119,7 +119,7 @@
</div> </div>
<ng-template #featurebits let-bits="bits"> <ng-template #featurebits let-bits="bits">
<td i18n="lightning.features" class="text-truncate label">Features</td> <td i18n="transaction.features|Transaction features" class="text-truncate label">Features</td>
<td class="d-flex justify-content-between"> <td class="d-flex justify-content-between">
<span class="text-truncate w-90">{{ bits }}</span> <span class="text-truncate w-90">{{ bits }}</span>
<button type="button" class="btn btn-outline-info btn-xs" (click)="toggleFeatures()" i18n="transaction.details|Transaction Details">Details</button> <button type="button" class="btn btn-outline-info btn-xs" (click)="toggleFeatures()" i18n="transaction.details|Transaction Details">Details</button>
@ -133,11 +133,11 @@
<h5>Raw bits</h5> <h5>Raw bits</h5>
<span class="text-wrap w-100"><small>{{ node.featuresBits }}</small></span> <span class="text-wrap w-100"><small>{{ node.featuresBits }}</small></span>
</div> </div>
<h5>Decoded</h5> <h5 i18n="lightning.decoded|Decoded">Decoded</h5>
<table class="table table-borderless table-striped table-fixed"> <table class="table table-borderless table-striped table-fixed">
<thead> <thead>
<th style="width: 13%">Bit</th> <th style="width: 13%">Bit</th>
<th>Name</th> <th i18n="lightning.as-name">Name</th>
<th style="width: 25%; text-align: right">Required</th> <th style="width: 25%; text-align: right">Required</th>
</thead> </thead>
<tbody> <tbody>

View File

@ -1,22 +1,28 @@
<div class="map-wrapper" [class]="style"> <div class="map-wrapper" [class]="style" *ngIf="style !== 'graph'">
<ng-container *ngIf="channelsObservable | async"> <ng-container *ngIf="channelsObservable | async">
<div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')"> <div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')">
<div *ngIf="style === 'graph'" class="card-header">
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
<span i18n="lightning.nodes-channels-world-map">Lightning Nodes Channels World Map</span>
</div>
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
</div>
<div class="chart" [class]="style" echarts [initOpts]="chartInitOptions" [options]="chartOptions" <div class="chart" [class]="style" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
(chartInit)="onChartInit($event)" (chartFinished)="onChartFinished($event)"> (chartInit)="onChartInit($event)" (chartFinished)="onChartFinished($event)">
</div> </div>
<div *ngIf="!chartOptions && style === 'nodepage'" style="padding-top: 30px"></div> <div *ngIf="!chartOptions && style === 'nodepage'" style="padding-top: 30px"></div>
</div> </div>
<div class="text-center loading-spinner" [class]="style" *ngIf="isLoading && !disableSpinner"> <div class="text-center loading-spinner" [class]="style" *ngIf="isLoading && !disableSpinner">
<div class="spinner-border text-light"></div> <div class="spinner-border text-light"></div>
</div> </div>
</ng-container> </ng-container>
</div> </div>
<div class="full-container-graph" *ngIf="style === 'graph'">
<div class="card-header">
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
<span i18n="lightning.nodes-channels-world-map">Lightning Nodes Channels World Map</span>
</div>
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
</div>
<div *ngIf="channelsObservable | async" class="chart-graph" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
(chartInit)="onChartInit($event)" (chartFinished)="onChartFinished($event)">
</div>
</div>

View File

@ -143,3 +143,55 @@
text-align: center; text-align: center;
margin-top: 100px; margin-top: 100px;
} }
.full-container-graph {
display: flex;
flex-direction: column;
padding: 0px 15px;
width: 100%;
height: calc(100vh - 225px);
min-height: 400px;
@media (min-width: 992px) {
height: calc(100vh - 150px);
}
}
.full-container-graph.widget {
min-height: 240px;
height: 240px;
padding: 0px;
}
.full-container-graph.fit-container {
margin: 0;
padding: 0;
height: 100%;
min-height: 100px;
.chart {
padding: 0;
min-height: 100px;
}
}
.chart-graph {
display: flex;
flex: 1;
height: 100%;
padding-top: 30px;
padding-bottom: 20px;
padding-right: 10px;
@media (max-width: 992px) {
padding-bottom: 25px;
}
@media (max-width: 829px) {
padding-bottom: 50px;
}
@media (max-width: 767px) {
padding-bottom: 25px;
}
@media (max-width: 629px) {
padding-bottom: 55px;
}
@media (max-width: 567px) {
padding-bottom: 55px;
}
}

View File

@ -65,6 +65,7 @@ export class NodesChannelsMap implements OnInit {
} }
if (this.style === 'graph') { if (this.style === 'graph') {
this.center = [0, 5];
this.seoService.setTitle($localize`Lightning Nodes Channels World Map`); this.seoService.setTitle($localize`Lightning Nodes Channels World Map`);
this.seoService.setDescription($localize`:@@meta.description.lightning.node-map:See the channels of non-Tor Lightning network nodes visualized on a world map. Hover/tap on points on the map for node names and details.`); this.seoService.setDescription($localize`:@@meta.description.lightning.node-map:See the channels of non-Tor Lightning network nodes visualized on a world map. Hover/tap on points on the map for node names and details.`);
} }
@ -238,7 +239,6 @@ export class NodesChannelsMap implements OnInit {
title: title ?? undefined, title: title ?? undefined,
tooltip: {}, tooltip: {},
geo: { geo: {
top: 75,
animation: false, animation: false,
silent: true, silent: true,
center: this.center, center: this.center,

View File

@ -3,6 +3,7 @@ import { Inject, Injectable } from '@angular/core';
import { ApiService } from './api.service'; import { ApiService } from './api.service';
import { SeoService } from './seo.service'; import { SeoService } from './seo.service';
import { StateService } from './state.service'; import { StateService } from './state.service';
import { ActivatedRoute } from '@angular/router';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -11,12 +12,15 @@ export class EnterpriseService {
exclusiveHostName = '.mempool.space'; exclusiveHostName = '.mempool.space';
subdomain: string | null = null; subdomain: string | null = null;
info: object = {}; info: object = {};
statsUrl: string;
siteId: number;
constructor( constructor(
@Inject(DOCUMENT) private document: Document, @Inject(DOCUMENT) private document: Document,
private apiService: ApiService, private apiService: ApiService,
private seoService: SeoService, private seoService: SeoService,
private stateService: StateService, private stateService: StateService,
private activatedRoute: ActivatedRoute,
) { ) {
const subdomain = this.document.location.hostname.indexOf(this.exclusiveHostName) > -1 const subdomain = this.document.location.hostname.indexOf(this.exclusiveHostName) > -1
&& this.document.location.hostname.split(this.exclusiveHostName)[0] || false; && this.document.location.hostname.split(this.exclusiveHostName)[0] || false;
@ -56,7 +60,7 @@ export class EnterpriseService {
insertMatomo(siteId?: number): void { insertMatomo(siteId?: number): void {
let statsUrl = '//stats.mempool.space/'; let statsUrl = '//stats.mempool.space/';
if (!siteId) { if (!siteId) {
switch (this.document.location.hostname) { switch (this.document.location.hostname) {
case 'mempool.space': case 'mempool.space':
@ -88,16 +92,63 @@ export class EnterpriseService {
} }
} }
this.statsUrl = statsUrl;
this.siteId = siteId;
// @ts-ignore // @ts-ignore
const _paq = window._paq = window._paq || []; if (window._paq && window['Matomo']) {
_paq.push(['disableCookies']); window['Matomo'].addTracker(this.statsUrl+'m.php', this.siteId.toString());
_paq.push(['trackPageView']); const matomo = this.getMatomo();
_paq.push(['enableLinkTracking']); matomo.setDocumentTitle(this.seoService.getTitle());
(function() { matomo.setCustomUrl(this.getCustomUrl());
_paq.push(['setTrackerUrl', statsUrl+'m.php']); matomo.disableCookies();
_paq.push(['setSiteId', siteId.toString()]); matomo.trackPageView();
const d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; matomo.enableLinkTracking();
g.type='text/javascript'; g.async=true; g.src=statsUrl+'m.js'; s.parentNode.insertBefore(g,s); } else {
})(); // @ts-ignore
const alreadyInitialized = !!window._paq;
// @ts-ignore
const _paq = window._paq = window._paq || [];
_paq.push(['setDocumentTitle', this.seoService.getTitle()]);
_paq.push(['setCustomUrl', this.getCustomUrl()]);
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
if (alreadyInitialized) {
_paq.push(['addTracker', this.statsUrl+'m.php', this.siteId.toString()]);
} else {
(function() {
_paq.push(['setTrackerUrl', this.statsUrl+'m.php']);
_paq.push(['setSiteId', this.siteId.toString()]);
const d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
// @ts-ignore
g.type='text/javascript'; g.async=true; g.src=statsUrl+'m.js'; s.parentNode.insertBefore(g,s);
})();
}
}
}
private getMatomo() {
if (this.siteId != null) {
return window['Matomo']?.getTracker(this.statsUrl, this.siteId);
}
}
goal(id: number) {
// @ts-ignore
this.getMatomo()?.trackGoal(id);
}
private getCustomUrl(): string {
let url = window.location.origin + '/';
let route = this.activatedRoute;
while (route) {
const segment = route?.routeConfig?.path;
if (segment && segment.length) {
url += segment + '/';
}
route = route.firstChild;
}
return url;
} }
} }

View File

@ -10,7 +10,7 @@ import { StateService } from './state.service';
export class SeoService { export class SeoService {
network = ''; network = '';
baseTitle = 'mempool'; baseTitle = 'mempool';
baseDescription = 'Explore the full Bitcoin ecosystem with The Mempool Open Project™.'; baseDescription = 'Explore the full Bitcoin ecosystem with The Mempool Open Source Project™.';
canonicalLink: HTMLElement = document.getElementById('canonical'); canonicalLink: HTMLElement = document.getElementById('canonical');

View File

@ -1,4 +1,4 @@
<ng-container *ngIf="rateUnits$ | async as units"> <ng-container *ngIf="rateUnits$ | async as units">
<ng-container *ngIf="units !== 'wu'">{{ fee / (weight / 4) | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle">sat/vB</span></ng-container> <ng-container *ngIf="units !== 'wu'">{{ fee / (weight / 4) | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></ng-container>
<ng-container *ngIf="units === 'wu'">{{ fee / weight | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle">sat/WU</span></ng-container> <ng-container *ngIf="units === 'wu'">{{ fee / weight | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-weight-units|sat/WU">sat/WU</span></ng-container>
</ng-container> </ng-container>

View File

@ -38,45 +38,45 @@
</div> </div>
<div class="row col-md-12 link-tree" [class]="{'services': isServicesPage}"> <div class="row col-md-12 link-tree" [class]="{'services': isServicesPage}">
<div class="links"> <div class="links">
<p class="category">Explore</p> <p class="category" i18n="footer.explore">Explore</p>
<p><a [routerLink]="['/mining' | relativeUrl]">Mining Dashboard</a></p> <p><a [routerLink]="['/mining' | relativeUrl]" i18n="mining.mining-dashboard">Mining Dashboard</a></p>
<p><a *ngIf="env.LIGHTNING" [routerLink]="['/lightning' | relativeUrl]">Lightning Dashboard</a></p> <p><a *ngIf="env.LIGHTNING" [routerLink]="['/lightning' | relativeUrl]" i18n="master-page.lightning">Lightning Explorer</a></p>
<p><a [routerLink]="['/blocks' | relativeUrl]">Recent Blocks</a></p> <p><a [routerLink]="['/blocks' | relativeUrl]" i18n="dashboard.recent-blocks">Recent Blocks</a></p>
<p><a [routerLink]="['/tx/push' | relativeUrl]" i18n="shared.broadcast-transaction|Broadcast Transaction">Broadcast Transaction</a></p> <p><a [routerLink]="['/tx/push' | relativeUrl]" i18n="shared.broadcast-transaction|Broadcast Transaction">Broadcast Transaction</a></p>
<p *ngIf="officialMempoolSpace"><a [routerLink]="['/lightning/group/the-mempool-open-source-project' | relativeUrl]" i18n="footer.connect-to-our-nodes">Connect to our Nodes</a></p> <p *ngIf="officialMempoolSpace"><a [routerLink]="['/lightning/group/the-mempool-open-source-project' | relativeUrl]" i18n="footer.connect-to-our-nodes">Connect to our Nodes</a></p>
<p><a [routerLink]="['/docs/api' | relativeUrl]">API Documentation</a></p> <p><a [routerLink]="['/docs/api' | relativeUrl]" i18n="footer.api-documentation">API Documentation</a></p>
</div> </div>
<div class="links"> <div class="links">
<p class="category">Learn</p> <p class="category" i18n="footer.learn">Learn</p>
<p><a [routerLink]="['/docs/faq']" fragment="what-is-a-mempool">What is a mempool?</a></p> <p><a [routerLink]="['/docs/faq']" fragment="what-is-a-mempool" i18n="faq.what-is-a-mempool">What is a mempool?</a></p>
<p><a [routerLink]="['/docs/faq']" fragment="what-is-a-block-explorer">What is a block explorer?</a></p> <p><a [routerLink]="['/docs/faq']" fragment="what-is-a-block-explorer" i18n="faq.what-is-a-block-exlorer">What is a block explorer?</a></p>
<p><a [routerLink]="['/docs/faq']" fragment="what-is-a-mempool-explorer">What is a mempool explorer?</a></p> <p><a [routerLink]="['/docs/faq']" fragment="what-is-a-mempool-explorer" i18n="faq.what-is-a-mempool-exlorer">What is a mempool explorer?</a></p>
<p><a [routerLink]="['/docs/faq']" fragment="why-is-transaction-stuck-in-mempool">Why isn't my transaction confirming?</a></p> <p><a [routerLink]="['/docs/faq']" fragment="why-is-transaction-stuck-in-mempool" i18n="faq.why-isnt-my-transaction-confirming">Why isn't my transaction confirming?</a></p>
<p><a [routerLink]="['/docs/faq' | relativeUrl]">More FAQs </a></p> <p><a [routerLink]="['/docs/faq' | relativeUrl]" i18n="faq.more-faq">More FAQs &raquo;</a></p>
</div> </div>
<div class="links" *ngIf="officialMempoolSpace || env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.LIQUID_TESTNET_ENABLED else toolBox" > <div class="links" *ngIf="officialMempoolSpace || env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.LIQUID_TESTNET_ENABLED else toolBox" >
<p class="category">Networks</p> <p class="category" i18n="footer.networks">Networks</p>
<p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== '') && (currentNetwork !== 'mainnet')"><a [href]="networkLink('mainnet')">Mainnet Explorer</a></p> <p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== '') && (currentNetwork !== 'mainnet')"><a [href]="networkLink('mainnet')" i18n="footer.mainnet-explorer">Mainnet Explorer</a></p>
<p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== 'testnet') && env.TESTNET_ENABLED"><a [href]="networkLink('testnet')">Testnet Explorer</a></p> <p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== 'testnet') && env.TESTNET_ENABLED"><a [href]="networkLink('testnet')" i18n="footer.testnet-explorer">Testnet Explorer</a></p>
<p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== 'signet') && env.SIGNET_ENABLED"><a [href]="networkLink('signet')">Signet Explorer</a></p> <p *ngIf="(officialMempoolSpace || (env.BASE_MODULE === 'mempool')) && (currentNetwork !== 'signet') && env.SIGNET_ENABLED"><a [href]="networkLink('signet')" i18n="footer.signet-explorer">Signet Explorer</a></p>
<p *ngIf="(officialMempoolSpace || env.LIQUID_ENABLED) && (currentNetwork !== 'liquidtestnet')"><a [href]="networkLink('liquidtestnet')">Liquid Testnet Explorer</a></p> <p *ngIf="(officialMempoolSpace || env.LIQUID_ENABLED) && (currentNetwork !== 'liquidtestnet')"><a [href]="networkLink('liquidtestnet')" i18n="footer.liquid-testnet-explorer">Liquid Testnet Explorer</a></p>
<p *ngIf="(officialMempoolSpace || env.LIQUID_ENABLED) && (currentNetwork !== 'liquid')"><a [href]="networkLink('liquid')">Liquid Explorer</a></p> <p *ngIf="(officialMempoolSpace || env.LIQUID_ENABLED) && (currentNetwork !== 'liquid')"><a [href]="networkLink('liquid')" i18n="footer.liquid-explorer">Liquid Explorer</a></p>
<p *ngIf="(officialMempoolSpace && (currentNetwork !== 'bisq'))"><a [href]="networkLink('bisq')">Bisq Explorer</a></p> <p *ngIf="(officialMempoolSpace && (currentNetwork !== 'bisq'))"><a [href]="networkLink('bisq')" i18n="footer.bisq-explorer">Bisq Explorer</a></p>
</div> </div>
<ng-template #toolBox> <ng-template #toolBox>
<div class="links"> <div class="links">
<p class="category">Tools</p> <p class="category" i18n="footer.tools">Tools</p>
<p><a [routerLink]="['/clock/mempool/0']">Clock (Mempool)</a></p> <p><a [routerLink]="['/clock/mempool/0']" i18n="footer.clock-mempool">Clock (Mempool)</a></p>
<p><a [routerLink]="['/clock/mined/0']">Clock (Mined)</a></p> <p><a [routerLink]="['/clock/mined/0']" i18n="footer.clock-mined">Clock (Mined)</a></p>
<p><a [routerLink]="['/tools/calculator']">BTC/Fiat Converter</a></p> <p><a [routerLink]="['/tools/calculator']" i18n="shared.calculator">Calculator</a></p>
</div> </div>
</ng-template> </ng-template>
<div class="links"> <div class="links">
<p class="category">Legal</p> <p class="category" i18n="footer.legal">Legal</p>
<p><a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a></p> <p><a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a></p>
<p><a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a></p> <p><a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a></p>
<p><a [routerLink]="['/trademark-policy']">Trademark Policy</a></p> <p><a [routerLink]="['/trademark-policy']" i18n="shared.trademark-policy|Trademark Policy">Trademark Policy</a></p>
</div> </div>
</div> </div>
<div class="row social-links"> <div class="row social-links">

View File

@ -2,12 +2,12 @@ import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
const MempoolErrors = { const MempoolErrors = {
'internal_server_error': `Something went wrong, please try again later`,
'acceleration_duplicated': `This transaction has already been accelerated.`, 'acceleration_duplicated': `This transaction has already been accelerated.`,
'acceleration_outbid': `Your fee delta is too low.`, 'acceleration_outbid': `Your fee delta is too low.`,
'cannot_accelerate_tx': `Cannot accelerate this transaction.`, 'cannot_accelerate_tx': `Cannot accelerate this transaction.`,
'cannot_decode_raw_tx': `Cannot decode this raw transaction.`, 'cannot_decode_raw_tx': `Cannot decode this raw transaction.`,
'cannot_fetch_raw_tx': `Cannot find this transaction.`, 'cannot_fetch_raw_tx': `Cannot find this transaction.`,
'database_error': `Something went wrong. Please try again later.`,
'high_sigop_tx': `This transaction cannot be accelerated.`, 'high_sigop_tx': `This transaction cannot be accelerated.`,
'invalid_acceleration_request': `This acceleration request is not valid.`, 'invalid_acceleration_request': `This acceleration request is not valid.`,
'invalid_tx_dependencies': `This transaction dependencies are not valid.`, 'invalid_tx_dependencies': `This transaction dependencies are not valid.`,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff