Browse Source
Changelog additions: * Optional querying of UTXO set summary * Note: this is disabled by default to protect slow nodes. Set 'BTCEXP_SLOW_DEVICE_MODE' to false in your `.env` file to enjoy this feature. * More data in homepage "Network Summary": * Fee estimates (estimatesmartfee) for 1, 6, 144, 1008 blocks * Hashrate estimate for 1+7 days * New item for 'Chain Rewrite Days', using 7day hashrate * New data based on optional UTXO set summary (see note above): * UTXO set size * Total coins in circulation * Market cap * Tweaks to data in blocks lists: * Simpler timestamp formatting for easy reading * Include "Time-to-Mine" (TTM) for each block (with green/red highlighting for "fast"/"slow" (<5min/>15min) blocks) * Display average fee in sat/vB * Add total fees display * Demote display of "block size" value to hover * Show weight in kWu instead of Wu * Zero-indexing for tx inputs/outputs (#173) * Labels for transaction output types * Configurable UI "sub-header" links * Tweaked styling - Also lots of frontend code cleanup (moving to more consistent pug-style class designations)master
Dan Janosik
5 years ago
36 changed files with 1668 additions and 19960 deletions
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,54 +1,142 @@ |
|||
div(class="table-responsive") |
|||
table(class="table table-striped mb-0") |
|||
div.table-responsive |
|||
table.table.table-striped.mb-0 |
|||
thead |
|||
tr |
|||
//th |
|||
th(class="data-header") Height |
|||
th(class="data-header") Timestamp (utc) |
|||
th(class="data-header text-right") Age |
|||
th(class="data-header") Miner |
|||
th(class="data-header text-right") Transactions |
|||
th(class="data-header text-right") Average Fee |
|||
th(class="data-header text-right") Size (bytes) |
|||
th |
|||
th.data-header.text-right Height |
|||
th.data-header.text-right Date |
|||
small (utc) |
|||
th.data-header.text-right Age |
|||
th.data-header.text-right |
|||
span.border-dotted(title="Time To Mine - The time it took to mine this block after the previous block. 'Fast' blocks (mined in < 5min) are shown in green; 'slow' blocks (mined in > 15min) are shown in red.", data-toggle="tooltip") T.T.M. |
|||
th.data-header.text-right Miner |
|||
th.data-header.text-right Transactions |
|||
th.data-header.text-right Avg Fee |
|||
small (sat/vB) |
|||
th.data-header.text-right Total Fees |
|||
|
|||
//th.data-header.text-right Size (kB) |
|||
|
|||
if (blocks && blocks.length > 0 && blocks[0].weight) |
|||
th(class="data-header text-right") Weight (wu) |
|||
th.data-header.text-right Weight |
|||
small (kWu) |
|||
|
|||
else |
|||
th.data-header.text-right Size |
|||
small (kB) |
|||
tbody |
|||
|
|||
each block, blockIndex in blocks |
|||
if (block) |
|||
if (block && ((sort == "desc" && blockIndex < blocks.length - 1) || (sort == "asc" && (block.height == 0 || blockIndex > 0)))) |
|||
tr |
|||
td(class="data-cell monospace") |
|||
a(href=("/block-height/" + block.height)) #{block.height.toLocaleString()} |
|||
td |
|||
if (sort == "desc") |
|||
small.text-muted #{(blockIndex + offset + 1).toLocaleString()} |
|||
else |
|||
small.text-muted #{(blockIndex + offset).toLocaleString()} |
|||
|
|||
td.data-cell.text-monospace.text-right |
|||
if (global.specialBlocks && global.specialBlocks[block.hash]) |
|||
span |
|||
a(data-toggle="tooltip", title=(coinConfig.name + " Fun! See block for details")) |
|||
i(class="fas fa-certificate text-primary") |
|||
td(class="data-cell monospace") #{moment.utc(new Date(parseInt(block.time) * 1000)).format("Y-MM-DD HH:mm:ss")} |
|||
i.fas.fa-certificate.text-primary.mr-1 |
|||
|
|||
a(href=("/block-height/" + block.height)) #{block.height.toLocaleString()} |
|||
|
|||
|
|||
- var timeAgoTime = moment.utc(new Date()).diff(moment.utc(new Date(parseInt(block.time) * 1000))); |
|||
- var timeAgo = moment.duration(timeAgoTime); |
|||
|
|||
- var timeDiff = null; |
|||
|
|||
if (sort == "asc") |
|||
if (blockIndex > 0) |
|||
- var timeDiff = moment.duration(moment.utc(new Date(parseInt(block.time) * 1000)).diff(moment.utc(new Date(parseInt(blocks[blockIndex - 1].time) * 1000)))); |
|||
else |
|||
if (blockIndex < blocks.length - 1) |
|||
- var timeDiff = moment.duration(moment.utc(new Date(parseInt(block.time) * 1000)).diff(moment.utc(new Date(parseInt(blocks[blockIndex + 1].time) * 1000)))); |
|||
|
|||
td.data-cell.text-monospace.text-right |
|||
- var timestampHuman = block.time; |
|||
include timestamp-human.pug |
|||
|
|||
|
|||
td.data-cell.text-monospace.text-right |
|||
if (sort != "asc" && blockIndex == 0 && offset == 0 && timeAgoTime > (15 * 60 * 1000)) |
|||
span.text-danger.border-dotted(title="It's been > 15 min since this latest block.", data-toggle="tooltip") #{utils.shortenTimeDiff(timeAgo.format())} |
|||
else |
|||
span #{utils.shortenTimeDiff(timeAgo.format())} |
|||
|
|||
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(block.time) * 1000)))); |
|||
td(class="data-cell monospace text-right") #{timeAgo.format()} |
|||
td(class="data-cell monospace") |
|||
td.data-cell.text-monospace.text-right |
|||
if (timeDiff) |
|||
- var colorClass = "text-muted"; |
|||
if (timeDiff < 300000) |
|||
- var colorClass = "text-success"; |
|||
if (timeDiff > 900000) |
|||
- var colorClass = "text-danger"; |
|||
|
|||
span.font-weight-light(class=colorClass) #{utils.shortenTimeDiff(timeDiff.format())} |
|||
|
|||
else |
|||
if (block.height == 0) |
|||
small.border-dotted.text-muted(title="Not applicable: genesis block has no previous block to compare to.", data-toggle="tooltip") N/A (genesis) |
|||
else |
|||
span.font-weight-light.text-muted - |
|||
|
|||
td.data-cell.text-monospace.text-right |
|||
if (block.miner && block.miner.name) |
|||
span(data-toggle="tooltip", title=("Identified by: " + block.miner.identifiedBy), class="rounded bg-primary text-white px-2 py-1") #{block.miner.name} |
|||
small.rounded.bg-primary.text-white.px-2.py-1(data-toggle="tooltip", title=("Identified by: " + block.miner.identifiedBy)) #{utils.ellipsize(block.miner.name, 10)} |
|||
else |
|||
span ? |
|||
|
|||
|
|||
td(class="data-cell monospace text-right") #{block.tx.length.toLocaleString()} |
|||
td.data-cell.text-monospace.text-right #{block.tx.length.toLocaleString()} |
|||
|
|||
td(class="data-cell monospace text-right") |
|||
- var currencyValue = new Decimal(block.totalFees).dividedBy(block.tx.length); |
|||
td.data-cell.text-monospace.text-right |
|||
- var currencyValue = new Decimal(block.totalFees).dividedBy(block.strippedsize).times(coinConfig.baseCurrencyUnit.multiplier).toDecimalPlaces(1); |
|||
span #{currencyValue} |
|||
|
|||
// idea: show typical tx fee, maybe also optimized fee if not segwit |
|||
if (false) |
|||
- var feeEstimateVal = currencyValue.times(166).dividedBy(coinConfig.baseCurrencyUnit.multiplier); |
|||
span.border-dotted(title=`Value: ${feeEstimateVal}`, data-toggle="tooltip") #{currencyValue} |
|||
|
|||
td.data-cell.text-monospace.text-right |
|||
- var currencyValue = new Decimal(block.totalFees); |
|||
- var currencyValueDecimals = 3; |
|||
include ./value-display.pug |
|||
|
|||
|
|||
td(class="data-cell monospace text-right") #{block.size.toLocaleString()} |
|||
|
|||
if (false) |
|||
td.data-cell.text-monospace.text-right |
|||
- var bSizeK = parseInt(block.size / 1000); |
|||
span #{bSizeK.toLocaleString()} |
|||
|
|||
if (blocks && blocks.length > 0 && blocks[0].weight) |
|||
td(class="data-cell monospace text-right") |
|||
td.data-cell.text-monospace.text-right |
|||
- var bWeightK = parseInt(block.weight / 1000); |
|||
- var fullPercent = new Decimal(100 * block.weight / coinConfig.maxBlockWeight).toDecimalPlaces(1); |
|||
|
|||
span #{block.weight.toLocaleString()} |
|||
small(class="font-weight-light text-muted") (#{fullPercent}%) |
|||
span #{bWeightK.toLocaleString()} |
|||
small.font-weight-light.text-muted (#{fullPercent}%) |
|||
|
|||
- var bSizeK = parseInt(block.size / 1000); |
|||
span.ml-1(data-toggle="tooltip", title=`Size: ${bSizeK.toLocaleString()} kB`) |
|||
i.fas.fa-ellipsis-h.text-muted |
|||
|
|||
div(class="progress", style="height: 4px;") |
|||
div(class="progress-bar", role="progressbar", style=("width: " + fullPercent + "%;"), aria-valuenow=parseInt(100 * block.weight / coinConfig.maxBlockWeight), aria-valuemin="0" ,aria-valuemax="100") |
|||
div(class="progress-bar", role="progressbar", style=("width: " + fullPercent + "%;"), aria-valuenow=parseInt(100 * block.weight / coinConfig.maxBlockWeight), aria-valuemin="0" ,aria-valuemax="100") |
|||
|
|||
else |
|||
td.data-cell.text-monospace.text-right |
|||
- var bSizeK = parseInt(block.size / 1000); |
|||
- var fullPercent = new Decimal(100 * block.size / coinConfig.maxBlockSize).toDecimalPlaces(1); |
|||
|
|||
span #{bSizeK.toLocaleString()} |
|||
small.font-weight-light.text-muted (#{fullPercent}%) |
|||
|
|||
div(class="progress", style="height: 4px;") |
|||
div(class="progress-bar", role="progressbar", style=("width: " + fullPercent + "%;"), aria-valuenow=parseInt(100 * block.size / coinConfig.maxBlockSize), aria-valuemin="0" ,aria-valuemax="100") |
|||
|
|||
- var lastBlock = block; |
@ -0,0 +1,6 @@ |
|||
// debug as if we're in privacy mode (which means we don't have exchange rate data) |
|||
//- exchangeRates = null; |
|||
|
|||
// debug as if we're in performance protection mode (which means we don't calculate UTXO set details) |
|||
//- utxoSetSummary = null; |
|||
//- utxoSetSummaryPending = false; |
@ -0,0 +1,201 @@ |
|||
- var colClass = "col-lg-6 px-3"; |
|||
if (exchangeRates) |
|||
- colClass = "col-lg-4 px-3"; |
|||
|
|||
- var utxoCalculatingDesc = "At startup the app pulls a summary of the UTXO set. Until this summary is retrieved this data can't be displayed. Wait for the summary request to your node to return, then refresh this page."; |
|||
|
|||
div.row.index-summary |
|||
div(class=colClass) |
|||
h5.h6 Mining |
|||
|
|||
- var hashrate1dayData0 = utils.formatLargeNumber(hashrate1d, 0); |
|||
- var hashrate7dayData0 = utils.formatLargeNumber(hashrate7d, 0); |
|||
- var hashrate1dayData1 = utils.formatLargeNumber(hashrate1d, 1); |
|||
- var hashrate7dayData1 = utils.formatLargeNumber(hashrate7d, 1); |
|||
table.table.table-borderless.table-sm.table-hover |
|||
tbody |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-tachometer-alt.mr-1.summary-icon |
|||
span.border-dotted(title="Estimates for global network hashrate for 1 day / 7 days.", data-toggle="tooltip") Hashrate |
|||
small.ml-1 (d/w) |
|||
td.text-right.text-monospace |
|||
span.d-xxl-none #{hashrate1dayData0[0]} |
|||
span.d-none.d-xxl-inline #{hashrate1dayData1[0]} |
|||
small.text-muted / |
|||
span.d-xxl-none #{hashrate7dayData0[0]} |
|||
span.d-none.d-xxl-inline #{hashrate7dayData1[0]} |
|||
small.border-dotted(title=`${hashrate1dayData0[1].abbreviation}H = ${hashrate1dayData0[1].name}-hash (x10^${hashrate1dayData0[1].exponent})`, data-toggle="tooltip") #{hashrate1dayData0[1].abbreviation}H/s |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-edit.mr-1.summary-icon |
|||
span.border-dotted(title="Estimate of the number of days the current global hashrate would require to produce all the hashes needed to re-write the entire blockchain.", data-toggle="tooltip") Chain Rewrite Days |
|||
td.text-right.text-monospace |
|||
- var globalHashCount = parseInt("0x" + getblockchaininfo.chainwork); |
|||
- var rewriteDays = globalHashCount / hashrate7d / 60 / 60 / 24; |
|||
span #{new Decimal(rewriteDays).toDecimalPlaces(1)} |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-dumbbell.mr-1.summary-icon |
|||
span Difficulty |
|||
td.text-right.text-monospace |
|||
- var difficultyData = utils.formatLargeNumber(getblockchaininfo.difficulty, 2); |
|||
span.border-dotted(data-toggle="tooltip", title=parseFloat(getblockchaininfo.difficulty).toLocaleString()) |
|||
span #{difficultyData[0]} |
|||
small.px-2.px-lg-0.px-xl-2 x |
|||
span 10 |
|||
sup #{difficultyData[1].exponent} |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-unlock-alt.mr-1.summary-icon |
|||
span Unconfirmed Tx |
|||
td.text-right.text-monospace |
|||
- var colorClass = "text-success"; |
|||
if (mempoolInfo.size > 7000) |
|||
- colorClass = "text-warning"; |
|||
if (mempoolInfo.size > 11000) |
|||
- colorClass = "text-danger"; |
|||
|
|||
span(class=colorClass) #{mempoolInfo.size.toLocaleString()} |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-poll.mr-1.summary-icon |
|||
span.border-dotted(title="Current fee estimates (using 'estimatesmartfee') for getting a transaction included in 1 block, 6 blocks (1 hr), 144 blocks (1 day), or 1,008 blocks (1 week).", data-toggle="tooltip") Fee Targets |
|||
if (false) |
|||
small.ml-1 (1/h/d/w) |
|||
td.text-right.text-monospace #{smartFeeEsimates[1]} |
|||
small.d-md-none |
|||
small.text-muted / |
|||
span #{smartFeeEsimates[6]} |
|||
small.text-muted / |
|||
span #{smartFeeEsimates[144]} |
|||
small.text-muted / |
|||
span #{smartFeeEsimates[1008]} |
|||
small sat/vB |
|||
|
|||
div(class=colClass) |
|||
h5.h6 Blockchain |
|||
|
|||
table.table.table-borderless.table-sm.table-hover |
|||
tbody |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-sign-out-alt.mr-1.summary-icon |
|||
//span Total Transactions |
|||
span Total Txs |
|||
td.text-right.text-monospace |
|||
- var totalTxData = utils.formatLargeNumber(txStats.totalTxCount, 2); |
|||
span.border-dotted(title=`${txStats.totalTxCount.toLocaleString()}`, data-toggle="tooltip") #{totalTxData[0]} #{totalTxData[1].abbreviation} |
|||
|
|||
if (getblockchaininfo.size_on_disk) |
|||
- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 2); |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-database.mr-1.summary-icon |
|||
span Data Size |
|||
td.text-right.text-monospace #{sizeData[0]} #{sizeData[1].abbreviation}B |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-bolt.mr-1.summary-icon |
|||
span.border-dotted(title="The total amount of work necessary to produce the active chain, approximated in 'hashes'.", data-toggle="tooltip") Chain Work |
|||
td.text-right.text-monospace |
|||
- var chainworkData = utils.formatLargeNumber(parseInt("0x" + getblockchaininfo.chainwork), 2); |
|||
span.border-dotted(data-toggle="tooltip", title=`hex: ${getblockchaininfo.chainwork.replace(/^0+/, '')}`) |
|||
span #{chainworkData[0]} |
|||
small.px-2.px-lg-0.px-xl-2 x |
|||
span 10 |
|||
sup #{chainworkData[1].exponent} |
|||
|
|||
if (false) |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-arrow-circle-up.mr-1.summary-icon |
|||
span.border-dotted(title="The active 'soft' forks on the network.", data-toggle="tooltip") Soft-Forks |
|||
td.text-right.text-monospace.word-wrap |
|||
ul.list-inline.mb-0 |
|||
each softforkData, softforkName in getblockchaininfo.softforks |
|||
li.list-inline-item |
|||
small.border-dotted(title=`${JSON.stringify(softforkData)}`, data-toggle="tooltip") #{softforkName} |
|||
|
|||
|
|||
if (utxoSetSummary || utxoSetSummaryPending) |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-grip-horizontal.mr-1.summary-icon |
|||
span.border-dotted(title="The number / data size of 'unspent transaction outputs' (UTXOs) in the blockchain.", data-toggle="tooltip") UTXO Set |
|||
td.text-right.text-monospace |
|||
if (utxoSetSummary) |
|||
- var utxoCount = utils.formatLargeNumber(utxoSetSummary.txouts, 2); |
|||
- var utxoDataSize = utils.formatLargeNumber(utxoSetSummary.disk_size, 2); |
|||
span #{utxoCount[0]} #{utxoCount[1].abbreviation} |
|||
small.text-muted / |
|||
span #{utxoDataSize[0]} #{utxoDataSize[1].abbreviation}B |
|||
else |
|||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating... |
|||
|
|||
if (utxoSetSummary || utxoSetSummaryPending) |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fab.fa-bitcoin.mr-1.summary-icon |
|||
span Total Supply |
|||
td.text-right.text-monospace |
|||
if (utxoSetSummary) |
|||
span.border-dotted(title=`${new Decimal(utxoSetSummary.total_amount).dividedBy(coinConfig.maxSupply).times(100).toDP(4)}% produced`, data-toggle="tooltip") #{parseFloat(utxoSetSummary.total_amount).toLocaleString()} |
|||
else |
|||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating... |
|||
|
|||
|
|||
if (exchangeRates) |
|||
div(class=colClass) |
|||
h5.h6 Financials |
|||
|
|||
table.table.table-borderless.table-sm.table-hover |
|||
tbody |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-money-bill-wave-alt.mr-1.summary-icon |
|||
span.border-dotted(data-toggle="tooltip", title=("Exchange-rate data from: " + coinConfig.exchangeRateData.jsonUrl)) Exchange Rate |
|||
td.text-right.text-monospace |
|||
span #{utils.formatValueInActiveCurrency(1.0)} |
|||
|
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fab.fa-btc.mr-1.summary-icon |
|||
span Sats Rate |
|||
td.text-right.text-monospace |
|||
- var satsRateData = utils.satoshisPerUnitOfActiveCurrency(); |
|||
span #{satsRateData.amt} |
|||
small #{satsRateData.unit} |
|||
|
|||
if (utxoSetSummary || utxoSetSummaryPending) |
|||
tr |
|||
th.px-2.px-lg-0.px-xl-2 |
|||
i.fas.fa-globe.mr-1.summary-icon |
|||
span Market Cap |
|||
td.text-right.text-monospace |
|||
if (utxoSetSummary) |
|||
- var activeCurrency = global.currencyFormatType.length > 0 ? global.currencyFormatType : "usd"; |
|||
- var xxx = utils.formatLargeNumber(parseFloat(utxoSetSummary.total_amount) * exchangeRates[activeCurrency], 1); |
|||
|
|||
if (activeCurrency == "eur") |
|||
span € |
|||
else |
|||
span $ |
|||
|
|||
span #{xxx[0]} |
|||
if (xxx[1].textDesc) |
|||
span #{xxx[1].textDesc} |
|||
else |
|||
span x 10 |
|||
sup #{xxx[1].exponent} |
|||
// ["154.9",{"val":1000000000,"name":"giga","abbreviation":"G","exponent":"9"}] |
|||
|
|||
else |
|||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating... |
|||
|
@ -0,0 +1,3 @@ |
|||
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timeAgoTime) * 1000)))); |
|||
|
|||
span #{utils.shortenTimeDiff(timeAgo.format())} ago |
@ -0,0 +1,10 @@ |
|||
span #{moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("M/D")} |
|||
|
|||
- var yearStr = moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("Y"); |
|||
- var nowYearStr = moment.utc(new Date()).format("Y"); |
|||
|
|||
if (yearStr != nowYearStr) |
|||
span , #{yearStr} |
|||
|
|||
span |
|||
span.border-dotted(title=`${moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("Y-MM-DD HH:mm:ss")}`, data-toggle="tooltip") #{moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("HH:mm")} |
@ -0,0 +1,6 @@ |
|||
- var siteTool = config.siteTools[toolsItemIndex]; |
|||
li.mb-2 |
|||
span(title=siteTool.desc, data-toggle="tooltip") |
|||
i.mr-1.fa-sm(class=siteTool.fontawesome, style="width: 24px;") |
|||
a(href=siteTool.url) |
|||
span #{siteTool.name} |
@ -1,19 +1,100 @@ |
|||
div(class="card mb-4 shadow-sm") |
|||
div(class="card-header") |
|||
h2(class="h6 mb-0") Tools |
|||
div(class="card-body") |
|||
div(class="row") |
|||
each item, index in [[0, 1, 2], [4, 3, 5], [6, 7, 8]] |
|||
div(class="col-md-4") |
|||
ul(style="list-style-type: none;", class="pl-0") |
|||
each toolIndex, toolIndexIndex in item |
|||
- var siteTool = config.siteTools[toolIndex]; |
|||
|
|||
li |
|||
div(class="float-left", style="height: 50px; width: 40px; margin-right: 10px;") |
|||
span |
|||
i(class=siteTool.fontawesome, class="fa-2x mr-2", style="margin-top: 6px;") |
|||
|
|||
a(href=siteTool.url) #{siteTool.name} |
|||
br |
|||
p #{siteTool.desc} |
|||
if (false) |
|||
div.card.mb-4.shadow-sm |
|||
div.card-header |
|||
h2.h6.mb-0 Tools |
|||
div.card-body |
|||
div.row |
|||
each item, index in [[0, 1, 2], [4, 3, 5], [6, 7, 8]] |
|||
div.col-md-4 |
|||
ul.pl-0(style="list-style-type: none;") |
|||
each toolIndex, toolIndexIndex in item |
|||
- var siteTool = config.siteTools[toolIndex]; |
|||
|
|||
li |
|||
div.float-left(style="height: 50px; width: 40px; margin-right: 10px;") |
|||
span |
|||
i(class=siteTool.fontawesome, class="fa-2x mr-2", style="margin-top: 6px;") |
|||
|
|||
a(href=siteTool.url) #{siteTool.name} |
|||
br |
|||
p #{siteTool.desc} |
|||
|
|||
if (false) |
|||
div.row |
|||
each list, listIndex in [[0, 1], [2, 3], [4, 9], [5, 6], [7, 8]] |
|||
div.col |
|||
ul.list-unstyled |
|||
each listItem in list |
|||
- var siteTool = config.siteTools[listItem]; |
|||
li.mb-2 |
|||
span(title=siteTool.desc, data-toggle="tooltip") |
|||
i.mr-2.fa-lg(class=siteTool.fontawesome, style="width: 30px;") |
|||
a(href=siteTool.url) |
|||
span #{siteTool.name} |
|||
|
|||
if (false) |
|||
div.row |
|||
each list, listIndex in [[0, 1, 2, 3, 4], [9, 5, 6, 7, 8]] |
|||
div.col |
|||
ul.list-unstyled |
|||
each listItem in list |
|||
- var siteTool = config.siteTools[listItem]; |
|||
li.mb-2 |
|||
span(title=siteTool.desc, data-toggle="tooltip") |
|||
i.mr-2.fa-sm(class=siteTool.fontawesome, style="width: 30px;") |
|||
a(href=siteTool.url) |
|||
span #{siteTool.name} |
|||
|
|||
if (true) |
|||
div.row |
|||
// split into 4 segments: |
|||
// xxl: 2 columns (2 col because on xxl the tools card is in the same row as the "Network Summary" card) |
|||
// md: 3 columns (requires separate layout implementation...see below) |
|||
// lg, xl: 4 columns |
|||
// xm: 2 columns |
|||
- var indexLists = [[0, 1, 2], [3, 4, 9], [5, 6], [7, 8]]; |
|||
- var indexListsMediumWidth = [[0, 1, 2, 3], [4, 9, 5], [6, 7, 8]]; |
|||
|
|||
// special case for medium-width layout |
|||
div.col.d-none.d-md-block.d-lg-none |
|||
div.row |
|||
div.col-md-4 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexListsMediumWidth[0] |
|||
include tools-card-block.pug |
|||
|
|||
div.col-md-4 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexListsMediumWidth[1] |
|||
include tools-card-block.pug |
|||
|
|||
div.col-md-4 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexListsMediumWidth[2] |
|||
include tools-card-block.pug |
|||
|
|||
|
|||
// the below 2 div.col's are the default layout, used everywhere except medium-width layout |
|||
div.col.d-sm-block.d-md-none.d-lg-block |
|||
div.row |
|||
div.col-md-6.col-xxl-12 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexLists[0] |
|||
include tools-card-block.pug |
|||
|
|||
div.col-md-6.col-xxl-12 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexLists[1] |
|||
include tools-card-block.pug |
|||
|
|||
div.col.d-md-none.d-lg-block |
|||
div.row |
|||
div.col-md-6.col-xxl-12 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexLists[2] |
|||
include tools-card-block.pug |
|||
|
|||
div.col-md-6.col-xxl-12 |
|||
ul.list-unstyled.mb-0 |
|||
each toolsItemIndex in indexLists[3] |
|||
include tools-card-block.pug |
@ -1,18 +1,25 @@ |
|||
- var currencyFormatInfo = utils.getCurrencyFormatInfo(currencyFormatType); |
|||
|
|||
if (currencyValue > 0) |
|||
- var parts = utils.formatCurrencyAmount(currencyValue, currencyFormatType).split(" "); |
|||
if (currencyValueDecimals) |
|||
- var parts = utils.formatCurrencyAmountWithForcedDecimalPlaces(currencyValue, currencyFormatType, currencyValueDecimals); |
|||
else |
|||
- var parts = utils.formatCurrencyAmount(currencyValue, currencyFormatType); |
|||
|
|||
span.monospace #{parts[0]} |
|||
if (currencyFormatInfo.type == "native") |
|||
if (global.exchangeRates) |
|||
small.border-dotted.ml-1(data-toggle="tooltip", title=utils.formatExchangedCurrency(currencyValue, "usd")) #{parts[1]} |
|||
//span #{JSON.stringify(currencyFormatInfo)} |
|||
span.text-monospace #{parts.val}#{(currencyValueDecimals && currencyFormatInfo.type == "native" && currencyFormatInfo.multiplier <= 1000) ? "…" : ""} |
|||
if (parts.lessSignificantDigits) |
|||
span.text-monospace.text-small(style="margin-left: 2px;") #{parts.lessSignificantDigits} |
|||
|
|||
else |
|||
small.ml-1 #{parts[1]} |
|||
|
|||
else if (currencyFormatInfo.type == "exchanged") |
|||
small.border-dotted.ml-1(data-toggle="tooltip", title=utils.formatCurrencyAmount(currencyValue, coinConfig.defaultCurrencyUnit.name)) #{parts[1]} |
|||
if (currencyFormatInfo.type == "native") |
|||
if (exchangeRates) |
|||
small.border-dotted.ml-1(data-toggle="tooltip", title=utils.formatExchangedCurrency(currencyValue, "usd")) #{parts.currencyUnit} |
|||
|
|||
else |
|||
small.ml-1 #{parts.currencyUnit} |
|||
|
|||
else if (currencyFormatInfo.type == "exchanged") |
|||
small.border-dotted.ml-1(data-toggle="tooltip", title=utils.formatCurrencyAmount(currencyValue, coinConfig.defaultCurrencyUnit.name)) #{parts.currencyUnit} |
|||
|
|||
else |
|||
span.text-monospace 0 |
Loading…
Reference in new issue