mirror of
https://github.com/mempool/mempool.git
synced 2025-03-03 09:39:17 +01:00
Merge branch 'master' into nymkappa/menu
This commit is contained in:
commit
339a21caaa
62 changed files with 231 additions and 68 deletions
|
@ -41,6 +41,7 @@ export class BisqAddressComponent implements OnInit, OnDestroy {
|
||||||
document.body.scrollTo(0, 0);
|
document.body.scrollTo(0, 0);
|
||||||
this.addressString = params.get('id') || '';
|
this.addressString = params.get('id') || '';
|
||||||
this.seoService.setTitle($localize`:@@bisq-address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
this.seoService.setTitle($localize`:@@bisq-address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.address:See current balance, pending transactions, and history of confirmed transactions for BSQ address ${this.addressString}:INTERPOLATION:.`);
|
||||||
|
|
||||||
return this.bisqApiService.getAddress$(this.addressString)
|
return this.bisqApiService.getAddress$(this.addressString)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -88,6 +88,7 @@ export class BisqBlockComponent implements OnInit, OnDestroy {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.blockHeight = block.height;
|
this.blockHeight = block.height;
|
||||||
this.seoService.setTitle($localize`:@@bisq-block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.hash}:BLOCK_HASH:`);
|
this.seoService.setTitle($localize`:@@bisq-block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.hash}:BLOCK_HASH:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.block:See all BSQ transactions in Bitcoin block ${block.height}:BLOCK_HEIGHT: (block hash ${block.hash}:BLOCK_HASH:).`);
|
||||||
this.block = block;
|
this.block = block;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ export class BisqBlocksComponent implements OnInit {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`);
|
this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.blocks:See a list of recent Bitcoin blocks with BSQ transactions, total BSQ sent per block, and more.`);
|
||||||
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
|
this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
|
||||||
this.loadingItems = Array(this.itemsPerPage);
|
this.loadingItems = Array(this.itemsPerPage);
|
||||||
if (document.body.clientWidth < 670) {
|
if (document.body.clientWidth < 670) {
|
||||||
|
|
|
@ -29,7 +29,8 @@ export class BisqDashboardComponent implements OnInit {
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle(`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.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
|
|
||||||
this.volumes$ = this.bisqApiService.getAllVolumesDay$()
|
this.volumes$ = this.bisqApiService.getAllVolumesDay$()
|
||||||
|
|
|
@ -34,6 +34,7 @@ export class BisqMainDashboardComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.resetTitle();
|
this.seoService.resetTitle();
|
||||||
|
this.seoService.resetDescription();
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
|
|
||||||
this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(
|
this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(
|
||||||
|
|
|
@ -48,7 +48,8 @@ export class BisqMarketComponent implements OnInit, OnDestroy {
|
||||||
map(([markets, routeParams]) => {
|
map(([markets, routeParams]) => {
|
||||||
const pair = routeParams.get('pair');
|
const pair = routeParams.get('pair');
|
||||||
const pairUpperCase = pair.replace('_', '/').toUpperCase();
|
const pairUpperCase = pair.replace('_', '/').toUpperCase();
|
||||||
this.seoService.setTitle(`Bisq market: ${pairUpperCase}`);
|
this.seoService.setTitle($localize`:@@meta.title.bisq.market:Bisq market: ${pairUpperCase}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.market:See price history, current buy/sell offers, and latest trades for the ${pairUpperCase} market on Bisq.`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pair: pairUpperCase,
|
pair: pairUpperCase,
|
||||||
|
|
|
@ -26,6 +26,7 @@ export class BisqStatsComponent implements OnInit {
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
|
|
||||||
this.seoService.setTitle($localize`:@@2a30a4cdb123a03facc5ab8c5b3e6d8b8dbbc3d4:BSQ statistics`);
|
this.seoService.setTitle($localize`:@@2a30a4cdb123a03facc5ab8c5b3e6d8b8dbbc3d4:BSQ statistics`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.stats:See high-level stats on the BSQ economy: supply metrics, number of addresses, BSQ price, market cap, and more.`);
|
||||||
this.stateService.bsqPrice$
|
this.stateService.bsqPrice$
|
||||||
.subscribe((bsqPrice) => {
|
.subscribe((bsqPrice) => {
|
||||||
this.price = bsqPrice;
|
this.price = bsqPrice;
|
||||||
|
|
|
@ -48,6 +48,7 @@ export class BisqTransactionComponent implements OnInit, OnDestroy {
|
||||||
document.body.scrollTo(0, 0);
|
document.body.scrollTo(0, 0);
|
||||||
this.txId = params.get('id') || '';
|
this.txId = params.get('id') || '';
|
||||||
this.seoService.setTitle($localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`);
|
this.seoService.setTitle($localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.transaction:See inputs, outputs, transaction type, burnt amount, and more for transaction with txid ${this.txId}:INTERPOLATION:.`);
|
||||||
if (history.state.data) {
|
if (history.state.data) {
|
||||||
return of(history.state.data);
|
return of(history.state.data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ export class BisqTransactionsComponent implements OnInit, OnDestroy {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
this.seoService.setTitle($localize`:@@add4cd82e3e38a3110fe67b3c7df56e9602644ee:Transactions`);
|
this.seoService.setTitle($localize`:@@add4cd82e3e38a3110fe67b3c7df56e9602644ee:Transactions`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bisq.transactions:See recent BSQ transactions: amount, txid, associated Bitcoin block, transaction type, and more.`);
|
||||||
|
|
||||||
this.radioGroupForm = this.formBuilder.group({
|
this.radioGroupForm = this.formBuilder.group({
|
||||||
txTypes: [this.txTypesDefaultChecked],
|
txTypes: [this.txTypesDefaultChecked],
|
||||||
|
|
|
@ -43,6 +43,7 @@ export class AboutComponent implements OnInit {
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.backendInfo$ = this.stateService.backendInfo$;
|
this.backendInfo$ = this.stateService.backendInfo$;
|
||||||
this.seoService.setTitle($localize`:@@004b222ff9ef9dd4771b777950ca1d0e4cd4348a:About`);
|
this.seoService.setTitle($localize`:@@004b222ff9ef9dd4771b777950ca1d0e4cd4348a:About`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.about:Learn more about The Mempool Open Source Project™\: enterprise sponsors, individual sponsors, integrations, who contributes, FOSS licensing, and more.`);
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
|
|
||||||
this.profiles$ = this.apiService.getAboutPageProfiles$().pipe(
|
this.profiles$ = this.apiService.getAboutPageProfiles$().pipe(
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { AudioService } from '../../services/audio.service';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { of, merge, Subscription, Observable } from 'rxjs';
|
import { of, merge, Subscription, Observable } from 'rxjs';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { AddressInformation } from '../../interfaces/node-api.interface';
|
import { AddressInformation } from '../../interfaces/node-api.interface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -68,6 +69,7 @@ export class AddressPreviewComponent implements OnInit, OnDestroy {
|
||||||
this.addressString = this.addressString.toLowerCase();
|
this.addressString = this.addressString.toLowerCase();
|
||||||
}
|
}
|
||||||
this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`);
|
||||||
|
|
||||||
return (this.addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/)
|
return (this.addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/)
|
||||||
? this.electrsApiService.getPubKeyAddress$(this.addressString)
|
? this.electrsApiService.getPubKeyAddress$(this.addressString)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { AudioService } from '../../services/audio.service';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { of, merge, Subscription, Observable } from 'rxjs';
|
import { of, merge, Subscription, Observable } from 'rxjs';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { AddressInformation } from '../../interfaces/node-api.interface';
|
import { AddressInformation } from '../../interfaces/node-api.interface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -76,6 +77,7 @@ export class AddressComponent implements OnInit, OnDestroy {
|
||||||
this.addressString = this.addressString.toLowerCase();
|
this.addressString = this.addressString.toLowerCase();
|
||||||
}
|
}
|
||||||
this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`);
|
||||||
|
|
||||||
return merge(
|
return merge(
|
||||||
of(true),
|
of(true),
|
||||||
|
|
|
@ -40,6 +40,7 @@ export class AssetsNavComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`);
|
this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.liquid.assets:Explore all the assets issued on the Liquid network like L-BTC, L-CAD, USDT, and more.`);
|
||||||
this.typeaheadSearchFn = this.typeaheadSearch;
|
this.typeaheadSearchFn = this.typeaheadSearch;
|
||||||
|
|
||||||
this.searchForm = this.formBuilder.group({
|
this.searchForm = this.formBuilder.group({
|
||||||
|
|
|
@ -64,6 +64,7 @@ export class BlockFeeRatesGraphComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@ed8e33059967f554ff06b4f5b6049c465b92d9b3:Block Fee Rates`);
|
this.seoService.setTitle($localize`:@@ed8e33059967f554ff06b4f5b6049c465b92d9b3:Block Fee Rates`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fee-rates:See Bitcoin feerates visualized over time, including minimum and maximum feerates per block along with feerates at various percentiles.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
|
|
@ -65,6 +65,7 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@6c453b11fd7bd159ae30bc381f367bc736d86909:Block Fees`);
|
this.seoService.setTitle($localize`:@@6c453b11fd7bd159ae30bc381f367bc736d86909:Block Fees`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fees:See the average mining fees earned per Bitcoin block visualized in BTC and USD over time.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('1m');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('1m');
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
@ -192,7 +193,7 @@ export class BlockFeesGraphComponent implements OnInit {
|
||||||
{
|
{
|
||||||
name: 'Fees ' + this.currency,
|
name: 'Fees ' + this.currency,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
icon: 'roundRect',
|
icon: 'roundRect',
|
||||||
|
|
|
@ -61,6 +61,7 @@ export class BlockHealthGraphComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@d7d5fcf50179ad70c938491c517efb82de2c8146:Block Health`);
|
this.seoService.setTitle($localize`:@@d7d5fcf50179ad70c938491c517efb82de2c8146:Block Health`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-health:See Bitcoin block health visualized over time. Block health is a measure of how many expected transactions were included in an actual mined block. Expected transactions are determined using Mempool's re-implementation of Bitcoin Core's transaction selection algorithm.`);
|
||||||
this.miningWindowPreference = '24h';//this.miningService.getDefaultTimespan('24h');
|
this.miningWindowPreference = '24h';//this.miningService.getDefaultTimespan('24h');
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
|
|
@ -63,6 +63,7 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@8ba8fe810458280a83df7fdf4c614dfc1a826445:Block Rewards`);
|
this.seoService.setTitle($localize`:@@8ba8fe810458280a83df7fdf4c614dfc1a826445:Block Rewards`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-rewards:See Bitcoin block rewards in BTC and USD visualized over time. Block rewards are the total funds miners earn from the block subsidy and fees.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('3m');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('3m');
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
@ -191,7 +192,7 @@ export class BlockRewardsGraphComponent implements OnInit {
|
||||||
{
|
{
|
||||||
name: 'Rewards ' + this.currency,
|
name: 'Rewards ' + this.currency,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
},
|
},
|
||||||
icon: 'roundRect',
|
icon: 'roundRect',
|
||||||
|
|
|
@ -60,6 +60,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit {
|
||||||
let firstRun = true;
|
let firstRun = true;
|
||||||
|
|
||||||
this.seoService.setTitle($localize`:@@56fa1cd221491b6478998679cba2dc8d55ba330d:Block Sizes and Weights`);
|
this.seoService.setTitle($localize`:@@56fa1cd221491b6478998679cba2dc8d55ba330d:Block Sizes and Weights`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-sizes:See Bitcoin block sizes (MB) and block weights (weight units) visualized over time.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { SeoService } from '../../services/seo.service';
|
||||||
import { OpenGraphService } from '../../services/opengraph.service';
|
import { OpenGraphService } from '../../services/opengraph.service';
|
||||||
import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
|
import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -97,6 +98,11 @@ export class BlockPreviewComponent implements OnInit, OnDestroy {
|
||||||
this.blockHeight = block.height;
|
this.blockHeight = block.height;
|
||||||
|
|
||||||
this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
|
this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
|
||||||
|
if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
|
||||||
|
} else {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
|
||||||
|
}
|
||||||
this.isLoadingBlock = false;
|
this.isLoadingBlock = false;
|
||||||
this.setBlockSubsidy();
|
this.setBlockSubsidy();
|
||||||
if (block?.extras?.reward !== undefined) {
|
if (block?.extras?.reward !== undefined) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
||||||
import { detectWebGL } from '../../shared/graphs.utils';
|
import { detectWebGL } from '../../shared/graphs.utils';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { PriceService, Price } from '../../services/price.service';
|
import { PriceService, Price } from '../../services/price.service';
|
||||||
import { CacheService } from '../../services/cache.service';
|
import { CacheService } from '../../services/cache.service';
|
||||||
|
|
||||||
|
@ -261,6 +262,11 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
this.setNextAndPreviousBlockLink();
|
this.setNextAndPreviousBlockLink();
|
||||||
|
|
||||||
this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
|
this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
|
||||||
|
if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
|
||||||
|
} else {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`);
|
||||||
|
}
|
||||||
this.isLoadingBlock = false;
|
this.isLoadingBlock = false;
|
||||||
this.setBlockSubsidy();
|
this.setBlockSubsidy();
|
||||||
if (block?.extras?.reward !== undefined) {
|
if (block?.extras?.reward !== undefined) {
|
||||||
|
@ -325,7 +331,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.subscribe(([transactions, blockAudit]) => {
|
.subscribe(([transactions, blockAudit]) => {
|
||||||
if (transactions) {
|
if (transactions) {
|
||||||
this.strippedTransactions = transactions;
|
this.strippedTransactions = transactions;
|
||||||
} else {
|
} else {
|
||||||
|
@ -680,7 +686,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
this.setAuditAvailable(false);
|
this.setAuditAvailable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuditAvailableFromBlockHeight(blockHeight: number): boolean {
|
isAuditAvailableFromBlockHeight(blockHeight: number): boolean {
|
||||||
if (!this.auditSupported) {
|
if (!this.auditSupported) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -729,4 +735,4 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||||
this.block.canonical = block.id;
|
this.block.canonical = block.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { BlockExtended } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-blocks-list',
|
selector: 'app-blocks-list',
|
||||||
|
@ -35,6 +37,7 @@ export class BlocksList implements OnInit {
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
|
private seoService: SeoService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +53,14 @@ 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.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.`);
|
||||||
|
} else {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.blocks:See the most recent Bitcoin${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block reward, block size, and more.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this.blocks$ = combineLatest([
|
this.blocks$ = combineLatest([
|
||||||
this.fromHeightSubject.pipe(
|
this.fromHeightSubject.pipe(
|
||||||
switchMap((fromBlockHeight) => {
|
switchMap((fromBlockHeight) => {
|
||||||
|
@ -129,4 +140,4 @@ export class BlocksList implements OnInit {
|
||||||
isEllipsisActive(e): boolean {
|
isEllipsisActive(e): boolean {
|
||||||
return (e.offsetWidth < e.scrollWidth);
|
return (e.offsetWidth < e.scrollWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { MiningService } from '../../services/mining.service';
|
||||||
import { download } from '../../shared/graphs.utils';
|
import { download } from '../../shared/graphs.utils';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hashrate-chart',
|
selector: 'app-hashrate-chart',
|
||||||
|
@ -71,6 +72,7 @@ export class HashrateChartComponent implements OnInit {
|
||||||
this.miningWindowPreference = '1y';
|
this.miningWindowPreference = '1y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`:@@3510fc6daa1d975f331e3a717bdf1a34efa06dff:Hashrate & Difficulty`);
|
this.seoService.setTitle($localize`:@@3510fc6daa1d975f331e3a717bdf1a34efa06dff:Hashrate & Difficulty`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.hashrate:See hashrate and difficulty for the Bitcoin${seoDescriptionNetwork(this.network)} network visualized over time.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('3m');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('3m');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
|
@ -256,7 +258,7 @@ export class HashrateChartComponent implements OnInit {
|
||||||
let difficultyPowerOfTen = hashratePowerOfTen;
|
let difficultyPowerOfTen = hashratePowerOfTen;
|
||||||
let difficulty = tick.data[1];
|
let difficulty = tick.data[1];
|
||||||
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()) {
|
if (this.isMobile()) {
|
||||||
difficultyPowerOfTen = selectPowerOfTen(tick.data[1]);
|
difficultyPowerOfTen = selectPowerOfTen(tick.data[1]);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { switchMap, map, tap, filter } from 'rxjs/operators';
|
||||||
import { MempoolBlock, TransactionStripped } from '../../interfaces/websocket.interface';
|
import { MempoolBlock, TransactionStripped } from '../../interfaces/websocket.interface';
|
||||||
import { Observable, BehaviorSubject } from 'rxjs';
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -54,6 +55,7 @@ export class MempoolBlockComponent implements OnInit, OnDestroy {
|
||||||
const ordinal = this.getOrdinal(mempoolBlocks[this.mempoolBlockIndex]);
|
const ordinal = this.getOrdinal(mempoolBlocks[this.mempoolBlockIndex]);
|
||||||
this.ordinal$.next(ordinal);
|
this.ordinal$.next(ordinal);
|
||||||
this.seoService.setTitle(ordinal);
|
this.seoService.setTitle(ordinal);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.mempool-block:See stats for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} transactions in the mempool: fee range, aggregate size, and more. Mempool blocks are updated in real-time as the network receives new transactions.`);
|
||||||
mempoolBlocks[this.mempoolBlockIndex].isStack = mempoolBlocks[this.mempoolBlockIndex].blockVSize > this.stateService.blockVSize;
|
mempoolBlocks[this.mempoolBlockIndex].isStack = mempoolBlocks[this.mempoolBlockIndex].blockVSize > this.stateService.blockVSize;
|
||||||
return mempoolBlocks[this.mempoolBlockIndex];
|
return mempoolBlocks[this.mempoolBlockIndex];
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class MiningDashboardComponent implements OnInit, AfterViewInit {
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
this.seoService.setTitle($localize`:@@a681a4e2011bb28157689dbaa387de0dd0aa0c11:Mining Dashboard`);
|
this.seoService.setTitle($localize`:@@a681a4e2011bb28157689dbaa387de0dd0aa0c11:Mining Dashboard`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.mining.dashboard:Get real-time Bitcoin mining stats like hashrate, difficulty adjustment, block rewards, pool dominance, and more.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
@ -29,7 +30,7 @@ export class MiningDashboardComponent implements OnInit, AfterViewInit {
|
||||||
this.router.events.subscribe((e: NavigationStart) => {
|
this.router.events.subscribe((e: NavigationStart) => {
|
||||||
if (e.type === EventType.NavigationStart) {
|
if (e.type === EventType.NavigationStart) {
|
||||||
if (e.url.indexOf('graphs') === -1) { // The mining dashboard and the graph component are part of the same module so we can't use ngAfterViewInit in graphs.component.ts to blur the input
|
if (e.url.indexOf('graphs') === -1) { // The mining dashboard and the graph component are part of the same module so we can't use ngAfterViewInit in graphs.component.ts to blur the input
|
||||||
this.stateService.focusSearchInputDesktop();
|
this.stateService.focusSearchInputDesktop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,6 +56,7 @@ export class PoolRankingComponent implements OnInit {
|
||||||
this.miningWindowPreference = '1w';
|
this.miningWindowPreference = '1w';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
|
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.pool-ranking:See the top Bitcoin mining pools ranked by number of blocks mined, over your desired timeframe.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('24h');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
|
@ -116,7 +117,7 @@ export class PoolRankingComponent implements OnInit {
|
||||||
} else if (this.widget) {
|
} else if (this.widget) {
|
||||||
poolShareThreshold = 1;
|
poolShareThreshold = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: object[] = [];
|
const data: object[] = [];
|
||||||
let totalShareOther = 0;
|
let totalShareOther = 0;
|
||||||
let totalBlockOther = 0;
|
let totalBlockOther = 0;
|
||||||
|
|
|
@ -83,6 +83,7 @@ export class PoolPreviewComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.seoService.setTitle(poolStats.pool.name);
|
this.seoService.setTitle(poolStats.pool.name);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.mining.pool:See mining pool stats for ${poolStats.pool.name}\: most recent mined blocks, hashrate over time, total block reward to date, known coinbase addresses, and more.`);
|
||||||
let regexes = '"';
|
let regexes = '"';
|
||||||
for (const regex of poolStats.pool.regexes) {
|
for (const regex of poolStats.pool.regexes) {
|
||||||
regexes += regex + '", "';
|
regexes += regex + '", "';
|
||||||
|
|
|
@ -83,6 +83,7 @@ export class PoolComponent implements OnInit {
|
||||||
}),
|
}),
|
||||||
map((poolStats) => {
|
map((poolStats) => {
|
||||||
this.seoService.setTitle(poolStats.pool.name);
|
this.seoService.setTitle(poolStats.pool.name);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.mining.pool:See mining pool stats for ${poolStats.pool.name}\: most recent mined blocks, hashrate over time, total block reward to date, known coinbase addresses, and more.`);
|
||||||
let regexes = '"';
|
let regexes = '"';
|
||||||
for (const regex of poolStats.pool.regexes) {
|
for (const regex of poolStats.pool.regexes) {
|
||||||
regexes += regex + '", "';
|
regexes += regex + '", "';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-privacy-policy',
|
selector: 'app-privacy-policy',
|
||||||
|
@ -11,5 +12,11 @@ export class PrivacyPolicyComponent {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private seoService: SeoService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.setTitle('Privacy Policy');
|
||||||
|
this.seoService.setDescription('Trusted third parties are security holes, as are trusted first parties...you should only trust your own self-hosted instance of The Mempool Open Source Project™.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-push-transaction',
|
selector: 'app-push-transaction',
|
||||||
|
@ -16,12 +19,17 @@ export class PushTransactionComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: UntypedFormBuilder,
|
private formBuilder: UntypedFormBuilder,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
public stateService: StateService,
|
||||||
|
private seoService: SeoService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.pushTxForm = this.formBuilder.group({
|
this.pushTxForm = this.formBuilder.group({
|
||||||
txHash: ['', Validators.required],
|
txHash: ['', Validators.required],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.push-tx:Broadcast Transaction`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.push-tx:Broadcast a transaction to the ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} network using the transaction's hash.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
postTx() {
|
postTx() {
|
||||||
|
|
|
@ -6,6 +6,8 @@ import { WebsocketService } from '../../services/websocket.service';
|
||||||
import { RbfTree } from '../../interfaces/node-api.interface';
|
import { RbfTree } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-rbf-list',
|
selector: 'app-rbf-list',
|
||||||
|
@ -26,6 +28,7 @@ export class RbfList implements OnInit, OnDestroy {
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
|
private seoService: SeoService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
@ -51,9 +54,12 @@ export class RbfList implements OnInit, OnDestroy {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.rbf-list: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.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.websocketService.stopTrackRbf();
|
this.websocketService.stopTrackRbf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ export class StatisticsComponent implements OnInit {
|
||||||
this.inverted = this.storageService.getValue('inverted-graph') === 'true';
|
this.inverted = this.storageService.getValue('inverted-graph') === 'true';
|
||||||
this.setFeeLevelDropdownData();
|
this.setFeeLevelDropdownData();
|
||||||
this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
|
this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.mempool:See mempool size (in MvB) and transactions per second (in vB/s) visualized over time.`);
|
||||||
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
||||||
this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h';
|
this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h';
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class TelevisionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.seoService.setTitle($localize`:@@46ce8155c9ab953edeec97e8950b5a21e67d7c4e:TV view`);
|
this.seoService.setTitle($localize`:@@46ce8155c9ab953edeec97e8950b5a21e67d7c4e:TV view`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.tv:See Bitcoin blocks and mempool congestion in real-time in a simplified format perfect for a TV.`);
|
||||||
this.websocketService.want(['blocks', 'live-2h-chart', 'mempool-blocks']);
|
this.websocketService.want(['blocks', 'live-2h-chart', 'mempool-blocks']);
|
||||||
|
|
||||||
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-terms-of-service',
|
selector: 'app-terms-of-service',
|
||||||
|
@ -10,5 +11,11 @@ export class TermsOfServiceComponent {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private seoService: SeoService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.setTitle('Terms of Service');
|
||||||
|
this.seoService.setDescription('Out of respect for the Bitcoin community, the mempool.space website is Bitcoin Only and does not display any advertising.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-trademark-policy',
|
selector: 'app-trademark-policy',
|
||||||
|
@ -11,5 +12,11 @@ export class TrademarkPolicyComponent {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private seoService: SeoService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.seoService.setTitle('Trademark Policy');
|
||||||
|
this.seoService.setDescription('An overview of the trademarks registered by Mempool Space K.K. and The Mempool Open Source Project™ and what we consider to be lawful usage of those trademarks.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { CacheService } from '../../services/cache.service';
|
||||||
import { OpenGraphService } from '../../services/opengraph.service';
|
import { OpenGraphService } from '../../services/opengraph.service';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { CpfpInfo } from '../../interfaces/node-api.interface';
|
import { CpfpInfo } from '../../interfaces/node-api.interface';
|
||||||
import { LiquidUnblinding } from './liquid-ublinding';
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ export class TransactionPreviewComponent implements OnInit, OnDestroy {
|
||||||
this.seoService.setTitle(
|
this.seoService.setTitle(
|
||||||
$localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`
|
$localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`
|
||||||
);
|
);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.transaction:Get real-time status, addresses, fees, script info, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} transaction with txid {txid}.`);
|
||||||
this.resetTransaction();
|
this.resetTransaction();
|
||||||
return merge(
|
return merge(
|
||||||
of(true),
|
of(true),
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { AudioService } from '../../services/audio.service';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
import { StorageService } from '../../services/storage.service';
|
import { StorageService } from '../../services/storage.service';
|
||||||
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment } from '../../interfaces/node-api.interface';
|
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment } from '../../interfaces/node-api.interface';
|
||||||
import { LiquidUnblinding } from './liquid-ublinding';
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||||
|
@ -287,6 +288,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||||
this.seoService.setTitle(
|
this.seoService.setTitle(
|
||||||
$localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`
|
$localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`
|
||||||
);
|
);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.transaction:Get real-time status, addresses, fees, script info, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} transaction with txid {txid}.`);
|
||||||
this.resetTransaction();
|
this.resetTransaction();
|
||||||
return merge(
|
return merge(
|
||||||
of(true),
|
of(true),
|
||||||
|
@ -389,7 +391,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||||
this.blockConversion = price;
|
this.blockConversion = price;
|
||||||
})
|
})
|
||||||
).subscribe();
|
).subscribe();
|
||||||
|
|
||||||
setTimeout(() => { this.applyFragment(); }, 0);
|
setTimeout(() => { this.applyFragment(); }, 0);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
|
|
@ -69,6 +69,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
|
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
|
||||||
this.seoService.resetTitle();
|
this.seoService.resetTitle();
|
||||||
|
this.seoService.resetDescription();
|
||||||
this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
|
this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
|
||||||
this.websocketService.startTrackRbfSummary();
|
this.websocketService.startTrackRbfSummary();
|
||||||
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
||||||
|
|
|
@ -28,21 +28,6 @@ export class DocsComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.websocket.want(['blocks']);
|
this.websocket.want(['blocks']);
|
||||||
const url = this.route.snapshot.url;
|
|
||||||
if (url[0].path === "faq" ) {
|
|
||||||
this.activeTab = 0;
|
|
||||||
this.seoService.setTitle($localize`:@@docs.faq.button-title:FAQ`);
|
|
||||||
} else if( url[1].path === "rest" ) {
|
|
||||||
this.activeTab = 1;
|
|
||||||
this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`);
|
|
||||||
} else if( url[1].path === "websocket" ) {
|
|
||||||
this.activeTab = 2;
|
|
||||||
this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`);
|
|
||||||
} else {
|
|
||||||
this.activeTab = 3;
|
|
||||||
this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.showWebSocketTab = ( ! ( ( this.stateService.network === "bisq" ) || ( this.stateService.network === "liquidtestnet" ) ) );
|
this.showWebSocketTab = ( ! ( ( this.stateService.network === "bisq" ) || ( this.stateService.network === "liquidtestnet" ) ) );
|
||||||
this.showFaqTab = ( this.env.BASE_MODULE === 'mempool' ) ? true : false;
|
this.showFaqTab = ( this.env.BASE_MODULE === 'mempool' ) ? true : false;
|
||||||
|
@ -51,6 +36,40 @@ export class DocsComponent implements OnInit {
|
||||||
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "smooth";
|
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "smooth";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngDoCheck(): void {
|
||||||
|
|
||||||
|
const url = this.route.snapshot.url;
|
||||||
|
|
||||||
|
if (url[0].path === "faq" ) {
|
||||||
|
this.activeTab = 0;
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.docs.faq:FAQ`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.faq:Get answers to common questions like: What is a mempool? Why isn't my transaction confirming? How can I run my own instance of The Mempool Open Source Project? And more.`);
|
||||||
|
} else if( url[1].path === "rest" ) {
|
||||||
|
this.activeTab = 1;
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.docs.rest:REST API`);
|
||||||
|
if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.rest-liquid:Documentation for the liquid.network REST API service: get info on addresses, transactions, assets, blocks, and more.`);
|
||||||
|
} else if( this.stateService.network === 'bisq' ) {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.rest-bisq:Documentation for the bisq.markets REST API service: get info on recent trades, current offers, transactions, network state, and more.`);
|
||||||
|
} else {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.rest-bitcoin:Documentation for the mempool.space REST API service: get info on addresses, transactions, blocks, fees, mining, the Lightning network, and more.`);
|
||||||
|
}
|
||||||
|
} else if( url[1].path === "websocket" ) {
|
||||||
|
this.activeTab = 2;
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.docs.websocket:WebSocket API`);
|
||||||
|
if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.websocket-liquid:Documentation for the liquid.network WebSocket API service: get real-time info on blocks, mempools, transactions, addresses, and more.`);
|
||||||
|
} else {
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.docs.websocket-bitcoin:Documentation for the mempool.space WebSocket API service: get real-time info on blocks, mempools, transactions, addresses, and more.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.activeTab = 3;
|
||||||
|
this.seoService.setTitle($localize`:@@meta.title.docs.websocket: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.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "auto";
|
document.querySelector<HTMLElement>( "html" ).style.scrollBehavior = "auto";
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ export class ChannelPreviewComponent implements OnInit {
|
||||||
this.openGraphService.waitFor('channel-data-' + this.shortId);
|
this.openGraphService.waitFor('channel-data-' + this.shortId);
|
||||||
this.error = null;
|
this.error = null;
|
||||||
this.seoService.setTitle(`Channel: ${params.get('short_id')}`);
|
this.seoService.setTitle(`Channel: ${params.get('short_id')}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.channel:Overview for Lightning channel ${params.get('short_id')}. See channel capacity, the Lightning nodes involved, related on-chain transactions, and more.`);
|
||||||
return this.lightningApiService.getChannel$(params.get('short_id'))
|
return this.lightningApiService.getChannel$(params.get('short_id'))
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((data) => {
|
tap((data) => {
|
||||||
|
|
|
@ -35,6 +35,7 @@ export class ChannelComponent implements OnInit {
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((value) => {
|
tap((value) => {
|
||||||
this.seoService.setTitle($localize`Channel: ${value.short_id}`);
|
this.seoService.setTitle($localize`Channel: ${value.short_id}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.channel:Overview for Lightning channel ${value.short_id}. See channel capacity, the Lightning nodes involved, related on-chain transactions, and more.`);
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError((err) => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
|
|
|
@ -31,6 +31,7 @@ export class GroupPreviewComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle(`Mempool.Space Lightning Nodes`);
|
this.seoService.setTitle(`Mempool.Space Lightning Nodes`);
|
||||||
|
this.seoService.setDescription(`See all Lightning nodes run by mempool.space -- these are the nodes that provide the data on the mempool.space Lightning dashboard.`);
|
||||||
|
|
||||||
this.nodes$ = this.activatedRoute.paramMap
|
this.nodes$ = this.activatedRoute.paramMap
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -39,6 +39,7 @@ export class GroupComponent implements OnInit {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.seoService.setTitle(`Mempool.space Lightning Nodes`);
|
this.seoService.setTitle(`Mempool.space Lightning Nodes`);
|
||||||
|
this.seoService.setDescription(`See all Lightning nodes run by mempool.space -- these are the nodes that provide the data on the mempool.space Lightning dashboard.`);
|
||||||
|
|
||||||
this.nodes$ = this.lightningApiService.getNodGroupNodes$('mempool.space')
|
this.nodes$ = this.lightningApiService.getNodGroupNodes$('mempool.space')
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -25,6 +25,7 @@ export class LightningDashboardComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@142e923d3b04186ac6ba23387265d22a2fa404e0:Lightning Explorer`);
|
this.seoService.setTitle($localize`:@@142e923d3b04186ac6ba23387265d22a2fa404e0:Lightning Explorer`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.dashboard:Get stats on the Lightning network (aggregate capacity, connectivity, etc) and Lightning nodes (channels, liquidity, etc) and Lightning channels (status, fees, etc).`);
|
||||||
|
|
||||||
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
||||||
this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share());
|
this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share());
|
||||||
|
|
|
@ -49,6 +49,7 @@ export class NodePreviewComponent implements OnInit {
|
||||||
}),
|
}),
|
||||||
map((node) => {
|
map((node) => {
|
||||||
this.seoService.setTitle(`Node: ${node.alias}`);
|
this.seoService.setTitle(`Node: ${node.alias}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.node:Overview for the Lightning network node named ${node.alias}. See channels, capacity, location, fee stats, and more.`);
|
||||||
|
|
||||||
const socketsObject = [];
|
const socketsObject = [];
|
||||||
const socketTypesMap = {};
|
const socketTypesMap = {};
|
||||||
|
|
|
@ -60,6 +60,7 @@ export class NodeComponent implements OnInit {
|
||||||
}),
|
}),
|
||||||
map((node) => {
|
map((node) => {
|
||||||
this.seoService.setTitle($localize`Node: ${node.alias}`);
|
this.seoService.setTitle($localize`Node: ${node.alias}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.node:Overview for the Lightning network node named ${node.alias}. See channels, capacity, location, fee stats, and more.`);
|
||||||
this.clearnetSocketCount = 0;
|
this.clearnetSocketCount = 0;
|
||||||
this.torSocketCount = 0;
|
this.torSocketCount = 0;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
@Input() disableSpinner = false;
|
@Input() disableSpinner = false;
|
||||||
@Output() readyEvent = new EventEmitter();
|
@Output() readyEvent = new EventEmitter();
|
||||||
|
|
||||||
channelsObservable: Observable<any>;
|
channelsObservable: Observable<any>;
|
||||||
|
|
||||||
center: number[] | undefined;
|
center: number[] | undefined;
|
||||||
zoom: number | undefined;
|
zoom: number | undefined;
|
||||||
|
@ -41,7 +41,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
chartOptions: EChartsOption = {};
|
chartOptions: EChartsOption = {};
|
||||||
chartInitOptions = {
|
chartInitOptions = {
|
||||||
renderer: 'canvas',
|
renderer: 'canvas',
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private seoService: SeoService,
|
private seoService: SeoService,
|
||||||
|
@ -64,15 +64,16 @@ export class NodesChannelsMap implements OnInit {
|
||||||
this.zoom = 1.4;
|
this.zoom = 1.4;
|
||||||
this.center = [0, 10];
|
this.center = [0, 10];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.style === 'graph') {
|
if (this.style === 'graph') {
|
||||||
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.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['nodepage', 'channelpage'].includes(this.style)) {
|
if (['nodepage', 'channelpage'].includes(this.style)) {
|
||||||
this.nodeSize = 8;
|
this.nodeSize = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.channelsObservable = this.activatedRoute.paramMap
|
this.channelsObservable = this.activatedRoute.paramMap
|
||||||
.pipe(
|
.pipe(
|
||||||
delay(100),
|
delay(100),
|
||||||
|
@ -81,7 +82,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
if (this.style === 'channelpage' && this.channel.length === 0 || !this.hasLocation) {
|
if (this.style === 'channelpage' && this.channel.length === 0 || !this.hasLocation) {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return zip(
|
return zip(
|
||||||
this.assetsService.getWorldMapJson$,
|
this.assetsService.getWorldMapJson$,
|
||||||
this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''],
|
this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''],
|
||||||
|
@ -140,7 +141,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
// on top of each other
|
// on top of each other
|
||||||
let random = Math.random() * 2 * Math.PI;
|
let random = Math.random() * 2 * Math.PI;
|
||||||
let random2 = Math.random() * 0.01;
|
let random2 = Math.random() * 0.01;
|
||||||
|
|
||||||
if (!nodesPubkeys[node1UniqueId]) {
|
if (!nodesPubkeys[node1UniqueId]) {
|
||||||
nodes.push([
|
nodes.push([
|
||||||
channel[node1GpsLat] + random2 * Math.cos(random),
|
channel[node1GpsLat] + random2 * Math.cos(random),
|
||||||
|
@ -167,7 +168,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
const channelLoc = [];
|
const channelLoc = [];
|
||||||
channelLoc.push(nodesPubkeys[node1UniqueId].slice(0, 2));
|
channelLoc.push(nodesPubkeys[node1UniqueId].slice(0, 2));
|
||||||
channelLoc.push(nodesPubkeys[node2UniqueId].slice(0, 2));
|
channelLoc.push(nodesPubkeys[node2UniqueId].slice(0, 2));
|
||||||
channelsLoc.push(channelLoc);
|
channelsLoc.push(channelLoc);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +327,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
this.chartInstance.on('finished', () => {
|
this.chartInstance.on('finished', () => {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.style === 'widget') {
|
if (this.style === 'widget') {
|
||||||
this.chartInstance.getZr().on('click', (e) => {
|
this.chartInstance.getZr().on('click', (e) => {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
|
@ -335,7 +336,7 @@ export class NodesChannelsMap implements OnInit {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chartInstance.on('click', (e) => {
|
this.chartInstance.on('click', (e) => {
|
||||||
if (e.data) {
|
if (e.data) {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
|
|
|
@ -48,6 +48,7 @@ export class NodesMap implements OnInit, OnChanges {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`:@@af8560ca50882114be16c951650f83bca73161a7:Lightning Nodes World Map`);
|
this.seoService.setTitle($localize`:@@af8560ca50882114be16c951650f83bca73161a7:Lightning Nodes World Map`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.node-channel-map:See the locations of non-Tor Lightning network nodes visualized on a world map. Hover/tap on points on the map for node names and details.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.inputNodes$) {
|
if (!this.inputNodes$) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
||||||
this.miningWindowPreference = '3y';
|
this.miningWindowPreference = '3y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`:@@b420668a91f8ebaf6e6409c4ba87f1d45961d2bd:Lightning Nodes Per Network`);
|
this.seoService.setTitle($localize`:@@b420668a91f8ebaf6e6409c4ba87f1d45961d2bd:Lightning Nodes Per Network`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-network:See the number of Lightning network nodes visualized over time by network: clearnet only (IPv4, IPv6), darknet (Tor, I2p, cjdns), and both.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
|
@ -375,7 +376,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
||||||
// We create dummy duplicated series so when we use the data zoom, the y axis
|
// We create dummy duplicated series so when we use the data zoom, the y axis
|
||||||
// both scales properly
|
// both scales properly
|
||||||
const invisibleSerie = {...serie};
|
const invisibleSerie = {...serie};
|
||||||
invisibleSerie.name = 'ignored' + Math.random().toString();
|
invisibleSerie.name = 'ignored' + Math.random().toString();
|
||||||
invisibleSerie.stack = 'ignored';
|
invisibleSerie.stack = 'ignored';
|
||||||
invisibleSerie.yAxisIndex = 1;
|
invisibleSerie.yAxisIndex = 1;
|
||||||
invisibleSerie.lineStyle = {
|
invisibleSerie.lineStyle = {
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class NodesPerCountryChartComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`:@@9d3ad4c6623870d96b65fb7a708fed6ce7c20044:Lightning Nodes Per Country`);
|
this.seoService.setTitle($localize`:@@9d3ad4c6623870d96b65fb7a708fed6ce7c20044:Lightning Nodes Per Country`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-country-overview:See a geographical breakdown of the Lightning network: how many Lightning nodes are hosted in countries around the world, aggregate BTC capacity for each country, and more.`);
|
||||||
this.nodesPerCountryObservable$ = this.apiService.getNodesPerCountry$()
|
this.nodesPerCountryObservable$ = this.apiService.getNodesPerCountry$()
|
||||||
.pipe(
|
.pipe(
|
||||||
map(data => {
|
map(data => {
|
||||||
|
|
|
@ -33,6 +33,7 @@ export class NodesPerCountry implements OnInit {
|
||||||
.pipe(
|
.pipe(
|
||||||
map(response => {
|
map(response => {
|
||||||
this.seoService.setTitle($localize`Lightning nodes in ${response.country.en}`);
|
this.seoService.setTitle($localize`Lightning nodes in ${response.country.en}`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-country:Explore all the Lightning nodes hosted in ${response.country.en} and see an overview of each node's capacity, number of open channels, and more.`);
|
||||||
|
|
||||||
this.country = {
|
this.country = {
|
||||||
name: response.country.en,
|
name: response.country.en,
|
||||||
|
@ -47,7 +48,7 @@ export class NodesPerCountry implements OnInit {
|
||||||
iso: response.nodes[i].iso_code,
|
iso: response.nodes[i].iso_code,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const sumLiquidity = response.nodes.reduce((partialSum, a) => partialSum + a.capacity, 0);
|
const sumLiquidity = response.nodes.reduce((partialSum, a) => partialSum + a.capacity, 0);
|
||||||
const sumChannels = response.nodes.reduce((partialSum, a) => partialSum + a.channels, 0);
|
const sumChannels = response.nodes.reduce((partialSum, a) => partialSum + a.channels, 0);
|
||||||
const isps = {};
|
const isps = {};
|
||||||
|
@ -70,14 +71,14 @@ export class NodesPerCountry implements OnInit {
|
||||||
isps[node.isp].asns.push(node.as_number);
|
isps[node.isp].asns.push(node.as_number);
|
||||||
}
|
}
|
||||||
isps[node.isp].count++;
|
isps[node.isp].count++;
|
||||||
|
|
||||||
if (isps[node.isp].count > topIsp.count) {
|
if (isps[node.isp].count > topIsp.count) {
|
||||||
topIsp.count = isps[node.isp].count;
|
topIsp.count = isps[node.isp].count;
|
||||||
topIsp.id = isps[node.isp].asns.join(',');
|
topIsp.id = isps[node.isp].asns.join(',');
|
||||||
topIsp.name = node.isp;
|
topIsp.name = node.isp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: response.nodes,
|
nodes: response.nodes,
|
||||||
sumLiquidity: sumLiquidity,
|
sumLiquidity: sumLiquidity,
|
||||||
|
|
|
@ -42,6 +42,7 @@ export class NodesPerISPPreview implements OnInit {
|
||||||
id: this.route.snapshot.params.isp.split(',').join(', ')
|
id: this.route.snapshot.params.isp.split(',').join(', ')
|
||||||
};
|
};
|
||||||
this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
|
this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-isp:Browse all Bitcoin Lightning nodes using the ${response.isp} [AS${this.route.snapshot.params.isp}] ISP and see aggregate stats like total number of nodes, total capacity, and more for the ISP.`);
|
||||||
|
|
||||||
for (const i in response.nodes) {
|
for (const i in response.nodes) {
|
||||||
response.nodes[i].geolocation = <GeolocationData>{
|
response.nodes[i].geolocation = <GeolocationData>{
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class NodesPerISP implements OnInit {
|
||||||
id: this.route.snapshot.params.isp.split(',').join(', ')
|
id: this.route.snapshot.params.isp.split(',').join(', ')
|
||||||
};
|
};
|
||||||
this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
|
this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.nodes-isp:Browse all Bitcoin Lightning nodes using the ${response.isp} [AS${this.route.snapshot.params.isp}] ISP and see aggregate stats like total number of nodes, total capacity, and more for the ISP.`);
|
||||||
|
|
||||||
for (const i in response.nodes) {
|
for (const i in response.nodes) {
|
||||||
response.nodes[i].geolocation = <GeolocationData>{
|
response.nodes[i].geolocation = <GeolocationData>{
|
||||||
|
|
|
@ -25,6 +25,7 @@ export class OldestNodes implements OnInit {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`Oldest lightning nodes`);
|
this.seoService.setTitle($localize`Oldest lightning nodes`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.oldest:See the oldest nodes on the Lightning network along with their capacity, number of channels, location, etc.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? 10 : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? 10 : 100); ++i) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { LightningApiService } from '../../lightning-api.service';
|
||||||
export class TopNodesPerCapacity implements OnInit {
|
export class TopNodesPerCapacity implements OnInit {
|
||||||
@Input() nodes$: Observable<INodesRanking>;
|
@Input() nodes$: Observable<INodesRanking>;
|
||||||
@Input() widget: boolean = false;
|
@Input() widget: boolean = false;
|
||||||
|
|
||||||
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
||||||
skeletonRows: number[] = [];
|
skeletonRows: number[] = [];
|
||||||
currency$: Observable<string>;
|
currency$: Observable<string>;
|
||||||
|
@ -31,6 +31,7 @@ export class TopNodesPerCapacity implements OnInit {
|
||||||
|
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.liquidity:See Lightning nodes with the most BTC liquidity deployed along with high-level stats like number of open channels, location, node age, and more.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ export class TopNodesPerChannels implements OnInit {
|
||||||
|
|
||||||
if (this.widget === false) {
|
if (this.widget === false) {
|
||||||
this.seoService.setTitle($localize`:@@c50bf442cf99f6fc5f8b687c460f33234b879869:Connectivity Ranking`);
|
this.seoService.setTitle($localize`:@@c50bf442cf99f6fc5f8b687c460f33234b879869:Connectivity Ranking`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.ranking.channels:See Lightning nodes with the most channels open along with high-level stats like total node capacity, node age, and more.`);
|
||||||
|
|
||||||
this.topNodesPerChannels$ = this.apiService.getTopNodesByChannels$().pipe(
|
this.topNodesPerChannels$ = this.apiService.getTopNodesByChannels$().pipe(
|
||||||
map((ranking) => {
|
map((ranking) => {
|
||||||
|
|
|
@ -20,6 +20,7 @@ export class NodesRankingsDashboard implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`Top lightning nodes`);
|
this.seoService.setTitle($localize`Top lightning nodes`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.rankings-dashboard:See top the Lightning network nodes ranked by liquidity, connectivity, and age.`);
|
||||||
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
||||||
this.miningWindowPreference = '3y';
|
this.miningWindowPreference = '3y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`:@@ea8db27e6db64f8b940711948c001a1100e5fe9f:Lightning Network Capacity`);
|
this.seoService.setTitle($localize`:@@ea8db27e6db64f8b940711948c001a1100e5fe9f:Lightning Network Capacity`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.lightning.stats-chart:See the capacity of the Lightning network visualized over time in terms of the number of open channels and total bitcoin capacity.`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
|
|
|
@ -10,6 +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™.';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private titleService: Title,
|
private titleService: Title,
|
||||||
|
@ -52,6 +53,18 @@ export class SeoService {
|
||||||
this.resetTitle();
|
this.resetTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDescription(newDescription: string): void {
|
||||||
|
this.metaService.updateTag({ name: 'description', content: newDescription});
|
||||||
|
this.metaService.updateTag({ name: 'twitter:description', content: newDescription});
|
||||||
|
this.metaService.updateTag({ property: 'og:description', content: newDescription});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetDescription(): void {
|
||||||
|
this.metaService.updateTag({ name: 'description', content: this.getDescription()});
|
||||||
|
this.metaService.updateTag({ name: 'twitter:description', content: this.getDescription()});
|
||||||
|
this.metaService.updateTag({ property: 'og:description', content: this.getDescription()});
|
||||||
|
}
|
||||||
|
|
||||||
getTitle(): string {
|
getTitle(): string {
|
||||||
if (this.network === 'testnet')
|
if (this.network === 'testnet')
|
||||||
return this.baseTitle + ' - Bitcoin Testnet';
|
return this.baseTitle + ' - Bitcoin Testnet';
|
||||||
|
@ -66,6 +79,15 @@ export class SeoService {
|
||||||
return this.baseTitle + ' - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer';
|
return this.baseTitle + ' - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDescription(): string {
|
||||||
|
if ( (this.network === 'testnet') || (this.network === 'signet') || (this.network === '') || (this.network == 'mainnet') )
|
||||||
|
return this.baseDescription + ' See the real-time status of your transactions, browse network stats, and more.';
|
||||||
|
if ( (this.network === 'liquid') || (this.network === 'liquidtestnet') )
|
||||||
|
return this.baseDescription + ' See Liquid transactions & assets, get network info, and more.';
|
||||||
|
if (this.network === 'bisq')
|
||||||
|
return this.baseDescription + ' See Bisq market prices, trading activity, and more.';
|
||||||
|
}
|
||||||
|
|
||||||
ucfirst(str: string) {
|
ucfirst(str: string) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,4 +143,13 @@ export function nextRoundNumber(num: number): number {
|
||||||
const factor = log >= 3 ? Math.pow(10, log - 2) : 1;
|
const factor = log >= 3 ? Math.pow(10, log - 2) : 1;
|
||||||
num /= factor;
|
num /= factor;
|
||||||
return factor * (roundNumbers.find(val => val >= num) || roundNumbers[roundNumbers.length - 1]);
|
return factor * (roundNumbers.find(val => val >= num) || roundNumbers[roundNumbers.length - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function seoDescriptionNetwork(network: string): string {
|
||||||
|
if( network === 'liquidtestnet' || network === 'testnet' ) {
|
||||||
|
return ' Testnet';
|
||||||
|
} else if( network === 'signet' || network === 'testnet' ) {
|
||||||
|
return ' ' + network.charAt(0).toUpperCase() + network.slice(1);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
|
@ -7,18 +7,18 @@
|
||||||
<script src="/resources/config.js"></script>
|
<script src="/resources/config.js"></script>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="The Mempool Open Source Project® - Explore the full Bitcoin ecosystem.">
|
<meta name="description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Bisq market prices, trading activity, and more.">
|
||||||
|
|
||||||
<meta property="og:image" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
<meta property="og:image" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
||||||
<meta property="og:image:type" content="image/jpeg" />
|
<meta property="og:image:type" content="image/jpeg" />
|
||||||
|
<meta property="og:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Bisq market prices, trading activity, and more." />
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:site" content="https://bisq.markets/">
|
<meta name="twitter:site" content="https://bisq.markets/">
|
||||||
<meta property="twitter:creator" content="@bisq_network">
|
<meta name="twitter:creator" content="@bisq_network">
|
||||||
<meta property="twitter:title" content="The Mempool Open Source Project®">
|
<meta name="twitter:title" content="The Mempool Open Source Project®">
|
||||||
<meta property="twitter:description" content="Explore the full Bitcoin ecosystem with mempool.space™" />
|
<meta name="twitter:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Bisq market prices, trading activity, and more." />
|
||||||
<meta property="twitter:image:src" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
<meta name="twitter:image:src" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
||||||
<meta property="twitter:domain" content="bisq.markets">
|
<meta name="twitter:domain" content="bisq.markets">
|
||||||
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="msapplication-TileColor" content="#000000">
|
<meta name="msapplication-TileColor" content="#000000">
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
<script src="/resources/config.js"></script>
|
<script src="/resources/config.js"></script>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="The Mempool Open Source Project® - Explore the full Bitcoin ecosystem.">
|
<meta name="description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Liquid transactions & assets, get network info, and more.">
|
||||||
<meta property="og:image" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
<meta property="og:image" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
||||||
<meta property="og:image:type" content="image/png" />
|
<meta property="og:image:type" content="image/png" />
|
||||||
<meta property="og:image:width" content="1000" />
|
<meta property="og:image:width" content="1000" />
|
||||||
<meta property="og:image:height" content="500" />
|
<meta property="og:image:height" content="500" />
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="og:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Liquid transactions & assets, get network info, and more." />
|
||||||
<meta property="twitter:site" content="@mempool">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:creator" content="@mempool">
|
<meta name="twitter:site" content="@mempool">
|
||||||
<meta property="twitter:title" content="The Mempool Open Source Project®">
|
<meta name="twitter:creator" content="@mempool">
|
||||||
<meta property="twitter:description" content="Explore the full Bitcoin ecosystem with mempool.space™" />
|
<meta name="twitter:title" content="The Mempool Open Source Project®">
|
||||||
<meta property="twitter:image:src" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
<meta name="twitter:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Project™. See Liquid transactions & assets, get network info, and more." />
|
||||||
<meta property="twitter:domain" content="liquid.network">
|
<meta name="twitter:image:src" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
||||||
|
<meta name="twitter:domain" content="liquid.network">
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/resources/liquid/favicons/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/resources/liquid/favicons/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="48x48" href="/resources/liquid/favicons/favicon-48x48.png">
|
<link rel="icon" type="image/png" sizes="48x48" href="/resources/liquid/favicons/favicon-48x48.png">
|
||||||
|
|
|
@ -7,18 +7,19 @@
|
||||||
<script src="/resources/config.js"></script>
|
<script src="/resources/config.js"></script>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="The Mempool Open Source Project® - Explore the full Bitcoin ecosystem." />
|
<meta name="description" content="Explore the full Bitcoin ecosystem with The Mempool Open Source Project™. See the real-time status of your transactions, get network info, and more." />
|
||||||
<meta property="og:image" content="https://mempool.space/resources/mempool-space-preview.png" />
|
<meta property="og:image" content="https://mempool.space/resources/mempool-space-preview.png" />
|
||||||
<meta property="og:image:type" content="image/png" />
|
<meta property="og:image:type" content="image/png" />
|
||||||
<meta property="og:image:width" content="1000" />
|
<meta property="og:image:width" content="1000" />
|
||||||
<meta property="og:image:height" content="500" />
|
<meta property="og:image:height" content="500" />
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="og:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Source Project™. See the real-time status of your transactions, get network info, and more." />
|
||||||
<meta property="twitter:site" content="@mempool">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:creator" content="@mempool">
|
<meta name="twitter:site" content="@mempool">
|
||||||
<meta property="twitter:title" content="The Mempool Open Source Project®">
|
<meta name="twitter:creator" content="@mempool">
|
||||||
<meta property="twitter:description" content="Explore the full Bitcoin ecosystem with mempool.space™" />
|
<meta name="twitter:title" content="The Mempool Open Source Project®">
|
||||||
<meta property="twitter:image:src" content="https://mempool.space/resources/mempool-space-preview.png" />
|
<meta name="twitter:description" content="Explore the full Bitcoin ecosystem with The Mempool Open Source Project™. See the real-time status of your transactions, get network info, and more." />
|
||||||
<meta property="twitter:domain" content="mempool.space">
|
<meta name="twitter:image:src" content="https://mempool.space/resources/mempool-space-preview.png" />
|
||||||
|
<meta name="twitter:domain" content="mempool.space">
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/resources/favicons/apple-touch-icon.png">
|
<link rel="apple-touch-icon" sizes="180x180" href="/resources/favicons/apple-touch-icon.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/resources/favicons/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="/resources/favicons/favicon-32x32.png">
|
||||||
|
|
Loading…
Add table
Reference in a new issue