mirror of
https://github.com/janoside/btc-rpc-explorer.git
synced 2026-08-13 12:33:13 +02:00
-new fun item showing example of future-dated timelock (coinbase) tx -special-case code for mainnet genesis coinbase tx, to avoid indicating that satoshi spent these unspendable coins -tx details: skip displaying locktime when it's meaningless (the raw data is in the json if anyone wants it); show additional info about locktime meaning -tx details: show byte-size in addition to vByte size, if applicable -fix for recently broken donut chart on /mining-summary -changelog
876 lines
36 KiB
Text
876 lines
36 KiB
Text
mixin themeCss
|
|
link(id="light-theme-link-tag", rel="stylesheet", href=`./style/light.css?v=${cacheId}`, integrity="sha384-G+XehzyDofsc9ZlqIF7hYXsaYijKshaTro74HxGnvEmvNiv2lRjGxO8g8HShNBQG")
|
|
link(id="dark-theme-link-tag", rel=(userSettings.uiTheme == "dark" ? "stylesheet" : false), href=`./style/dark.css?v=${cacheId}`, integrity="sha384-xjIBl325k0VYsT0wAem/8jzIxea9FDLsVmHZG8STGMhLu+rDq/xlWxo/iR6oJQ6w")
|
|
|
|
|
|
mixin sharedScriptTags
|
|
script(src=`./js/jquery.min.js?v=${cacheId}`, integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK")
|
|
script(src=`./js/bootstrap.bundle.min.js?v=${cacheId}`, integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p")
|
|
script(defer, src=`./js/fontawesome.min.js?v=${cacheId}`, integrity="sha384-haqrlim99xjfMxRP6EWtafs0sB1WKcMdynwZleuUSwJR0mDeRYbhtY+KPMr+JL6f")
|
|
|
|
script(src=`./js/site.js?v=${cacheId}`, integrity="sha384-RNCa5sCPh1hkJyKAu8z5Hai8r9IxpVBF2W6GFhSb2JSuSlECW8d85ufzyXBSRwLZ")
|
|
|
|
|
|
mixin pageTitle(text, subtext, copyableSubtext=false)
|
|
.d-flex.justify-content-between
|
|
h1.fw-light.word-wrap.mb-1
|
|
| #{text}
|
|
|
|
if (block)
|
|
.text-right
|
|
block
|
|
|
|
h4.fw-light.word-wrap.mb-4 #{subtext}
|
|
if (copyableSubtext)
|
|
small
|
|
+copyTextButton(subtext)
|
|
|
|
//hr.mb-3
|
|
|
|
|
|
mixin sectionTitleBlock
|
|
h3.h5.mb-1.fw-light
|
|
block
|
|
|
|
|
|
mixin sectionTitle(text, toggle=false, toggleUniqueClass, toggleUserSettingName, toggleOpen, tooltipText)
|
|
if (false)
|
|
pre
|
|
code.json #{JSON.stringify(session.userSettings)}
|
|
|
|
h3.h5.mb-1.fw-light(class=(toggle && !toggleOpen ? "mb-section" : false), class=(!toggle || toggleOpen ? "d-block" : "d-none"))
|
|
if (tooltipText)
|
|
span.border-dotted(title=tooltipText, data-bs-toggle="tooltip")
|
|
| #{text}
|
|
|
|
else
|
|
| #{text}
|
|
|
|
if (toggle)
|
|
small(title=`Toggle ${text}`, data-bs-toggle="tooltip")
|
|
a.text-card-highlight.fs-6(href=`./changeSetting?name=${toggleUserSettingName}&value=false`)
|
|
i.toggle-plus-minus.far.ms-2(class=(toggleOpen ? "fa-minus-square" : "fa-plus-square"))
|
|
|
|
|
|
mixin contentSection(title, toggleable=false, toggleUserSettingName, defaultOpen=true, cardUi=true)
|
|
if (toggleable)
|
|
- var toggleUniqueClass = `section-${utils.getRandomString(10, "aA#")}`;
|
|
- var toggleOpen = userSettings[toggleUserSettingName] == null ? defaultOpen : (userSettings[toggleUserSettingName] == "true" || userSettings[toggleUserSettingName] == true);
|
|
|
|
if (title)
|
|
+sectionTitle(title, toggleable, toggleUniqueClass, toggleUserSettingName, toggleOpen)
|
|
|
|
.mb-section(class=toggleUniqueClass, style=(toggleable && !toggleOpen ? "display: none;" : false))
|
|
if (cardUi)
|
|
.card.mb-section.shadow-sm
|
|
.card-body
|
|
block
|
|
|
|
else
|
|
block
|
|
|
|
|
|
mixin summaryRow(itemCount)
|
|
- locals.summaryItemCount = itemCount;
|
|
- locals.summaryItemIndex = 0;
|
|
|
|
- locals.colCounts = {"sm": 1, "md": Math.min(itemCount, 3), "lg": Math.min(itemCount, 4), "xl": Math.min(itemCount, 5)};
|
|
- locals.rowCountsArray = utils.objectProperties(locals.colCounts).map(x => [x, locals.colCounts[x]]).map(x => [x[0], (Math.floor(itemCount / x[1]) + ((itemCount % x[1] > 0) ? 1 : 0))]);
|
|
- locals.rowCounts = {};
|
|
- locals.rowCountsArray.forEach(x => locals.rowCounts[x[0]] = x[1]);
|
|
|
|
//h1 #{itemCount} #{JSON.stringify(locals.rowCounts)}
|
|
|
|
.row.row-cols-1(class=utils.objectProperties(locals.colCounts).map(x => `row-cols-${x}-${locals.colCounts[x]}`).join(" "))
|
|
block
|
|
|
|
|
|
mixin summaryTitle(title, titleDesc, subtitle, subtitleDesc)
|
|
span.fs-6.text-uppercase.fw-light.text-card-highlight(class=(titleDesc ? "border-dotted" : false), class=(subtitle ? "me-2" : false), title=titleDesc, data-bs-toggle="tooltip", data-bs-html="true") #{title}
|
|
if (subtitle)
|
|
small.text-card-highlight.fw-light
|
|
| (
|
|
span(class=(subtitleDesc ? "border-dotted" : false), title=subtitleDesc, data-bs-toggle="tooltip", data-bs-html="true") #{subtitle}
|
|
| )
|
|
|
|
|
|
mixin summaryItem(title, titleDesc, subtitle, subtitleDesc)
|
|
- var rowIndexes = utils.objectProperties(locals.colCounts).map(x => [x, locals.colCounts[x]]).map(x => [x[0], Math.floor(locals.summaryItemIndex / x[1])]);
|
|
|
|
.col(class=(locals.summaryItemIndex == (locals.summaryItemCount - 1) ? "mb-0" : "mb-3"), class=rowIndexes.map(x => `mb-${x[0]}-${(x[1] < (locals.rowCounts[x[0]] - 1) ? "4" : "0")}`))
|
|
//span.text-danger (#{JSON.stringify(locals.rowCounts)})
|
|
.text-start.text-md-center
|
|
+summaryTitle(title, titleDesc, subtitle, subtitleDesc)
|
|
|
|
|
|
.lead.text-start.text-md-center
|
|
block
|
|
|
|
- locals.summaryItemIndex++;
|
|
|
|
|
|
// options keys:
|
|
// - blockHeightsByTxid
|
|
// - sharedBlockHeight (int)
|
|
// - showDates (true|false)
|
|
// - highlightAddress (address)
|
|
// - addrGainsByTxid (map)
|
|
// - addrLossesByTxid (map)
|
|
// - mempoolDetailsByTxid (map)
|
|
|
|
// txBlockHeightsByTxid_orSharedBlockHeight, showDates=false, highlightAddress, addrGainsByTxid, addrLossesByTxid)
|
|
mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
|
|
if (txCount > limit && !options.hidePagination)
|
|
.rounded-0.rounded-top.bg-content.border
|
|
.p-3
|
|
h6.fw-normal.mb-2 #{offset.toLocaleString()} - #{Math.min(offset + limit - 1, txCount - 1).toLocaleString()} of #{txCount.toLocaleString()}
|
|
+pagination(limit, offset, null, txCount, paginationBaseUrl)
|
|
|
|
|
|
//.mb-4.mb-md-3
|
|
.pb-4.pb-md-3.bg-tx-separator
|
|
|
|
|
|
each tx, txIndex in visibleTxs
|
|
- var txBlockHeight = null;
|
|
if (options.blockHeightsByTxid)
|
|
- txBlockHeight = options.blockHeightsByTxid[tx.txid];
|
|
else if (options.sharedBlockHeight != undefined)
|
|
- txBlockHeight = options.sharedBlockHeight;
|
|
|
|
- var tx_height_param = (!global.txindexAvailable && txBlockHeight) ? `@${txBlockHeight}` : '';
|
|
|
|
.border.bg-content.p-3(class=(txIndex == 0 && txCount <= limit ? "rounded-top" : false), class=(txCount <= limit && txIndex == (visibleTxs.length - 1) ? "rounded-bottom" : false))
|
|
if (tx && tx.txid)
|
|
.clearfix
|
|
.float-start
|
|
.mb-3.word-wrap
|
|
span.badge.bg-primary.fw-normal.me-2(title=`Index in Block: #${(txIndex + offset).toLocaleString()}`, data-bs-toggle="tooltip")
|
|
span.d-inline.d-sm-none.me-1 tx
|
|
| ##{(txIndex + offset).toLocaleString()}
|
|
|
|
a.d-inline.d-md-none.small(href=`./tx/${tx.txid}${tx_height_param}`) #{utils.ellipsizeMiddle(tx.txid, 24)}
|
|
a.d-none.d-md-inline.d-lg-none(href=`./tx/${tx.txid}${tx_height_param}`) #{utils.ellipsizeMiddle(tx.txid, 24)}
|
|
a.d-none.d-lg-inline(href=`./tx/${tx.txid}${tx_height_param}`) #{utils.ellipsizeMiddle(tx.txid, 48)}
|
|
|
|
if (global.specialTransactions && global.specialTransactions[tx.txid])
|
|
a.ms-2(data-bs-toggle="tooltip", title=`${coinConfig.name} Fun! There's something special about this transaction…`)
|
|
+funItemIcon
|
|
|
|
|
|
|
|
- var hasInputAddresses = false;
|
|
if (tx && tx.vin && inputsByTxid && inputsByTxid[tx.txid])
|
|
- var txInputs = inputsByTxid[tx.txid];
|
|
each txVin, txVinIndex in tx.vin
|
|
if (!txVin.coinbase)
|
|
- var vout = null;
|
|
if (txInputs[txVinIndex])
|
|
- var voutAddresses = utils.getVoutAddresses(txInputs[txVinIndex]);
|
|
|
|
if (voutAddresses.length > 0)
|
|
- hasInputAddresses = true;
|
|
|
|
if (hasInputAddresses)
|
|
.float-end
|
|
.d-block.d-sm-none
|
|
a(href="javascript:void(0)", onclick=`$(this).find(".toggle-icon").toggleClass("fa-plus-square").toggleClass("fa-minus-square"); $(".tx-input-address-${tx.txid}").toggle();`)
|
|
i.toggle-icon.far.fa-plus-square.text-muted.text-end.fa-lg
|
|
|
|
|
|
.float-start.float-sm-end.mt-n2.mt-sm-0.mb-2.mb-sm-0
|
|
.me-5.me-sm-n2
|
|
if (options.mempoolDetailsByTxid && options.mempoolDetailsByTxid[tx.txid])
|
|
- var mempoolDetails = options.mempoolDetailsByTxid[tx.txid].entry;
|
|
- var feeRate = new Decimal(mempoolDetails.fee).times(coinConfig.baseCurrencyUnit.multiplier).dividedBy(mempoolDetails.vsize);
|
|
|
|
+lightBadge
|
|
| #{parseInt(feeRate).toLocaleString()}
|
|
span.text-tiny.ms-tiny sat/vB
|
|
|
|
if (options.addrGainsByTxid && options.addrGainsByTxid[tx.txid])
|
|
+successBadge
|
|
span.me-tiny +
|
|
+valueDisplay(options.addrGainsByTxid[tx.txid])
|
|
|
|
if (options.addrLossesByTxid && options.addrLossesByTxid[tx.txid])
|
|
span.badge.bg-danger.me-2
|
|
span.me-tiny -
|
|
+valueDisplay(options.addrLossesByTxid[tx.txid])
|
|
|
|
if (options.addrGainsByTxid && options.addrLossesByTxid && !options.addrGainsByTxid[tx.txid] && !options.addrLossesByTxid[tx.txid])
|
|
span.badge.bg-danger.me-2(data-bs-toggle="tooltip", title="See transaction details for spent-from-this-address amount")
|
|
span.fw-light …
|
|
|
|
if (options.showConfirmations)
|
|
+darkBadge
|
|
if (txBlockHeight)
|
|
span(title=`${(options.currentBlockHeight - txBlockHeight + 1).toLocaleString()} confirmation${(options.currentBlockHeight - txBlockHeight > 1) ? "s" :""}`, data-bs-toggle="tooltip")
|
|
i.fas.fa-lock.fa-sm.me-1
|
|
- var confCount = options.currentBlockHeight - txBlockHeight + 1;
|
|
- var confData = utils.formatLargeNumber(confCount);
|
|
|
|
span.fw-light
|
|
if (confCount < 1000)
|
|
| #{confCount}
|
|
else
|
|
| #{parseInt(confData[0])}#{confData[1].abbreviation}
|
|
|
|
else
|
|
span(title=`Unconfirmed`, data-bs-toggle="tooltip")
|
|
i.fas.fa-lock.fa-sm.me-1
|
|
span.fw-light.text-danger 0
|
|
|
|
if (options.showDates && tx.time)
|
|
- var utcMoment = moment.utc(new Date(parseInt(tx.time) * 1000));
|
|
- var titleStr = `${utcMoment.format("Y-MM-DD HH:mm:ss")} utc`;
|
|
|
|
.d-none.d-md-inline
|
|
+darkBadge
|
|
i.far.fa-clock.fa-sm.me-1
|
|
|
|
span.fw-light(title=titleStr, data-bs-toggle="tooltip")
|
|
+timeAgo(tx.time, true)
|
|
|
|
|
|
hr.mb-4.mx-n3
|
|
|
|
.d-none.d-lg-block.border-end.mt-n4.mb-2(style="border-color: currentColor !important; height: 10px; width: 50%; opacity: 0.25;")
|
|
|
|
div
|
|
- var txInputs = inputsByTxid[tx.txid];
|
|
- var blockHeight = txBlockHeight != undefined ? txBlockHeight : -1;
|
|
- options.maxTxOutputDisplayCount = maxTxOutputDisplayCount;
|
|
|
|
if (options.highlightAddress)
|
|
- var txIOHighlightAddress = options.highlightAddress;
|
|
|
|
include ./transaction-io-details.pug
|
|
|
|
if (txIndex < (visibleTxs.length - 1) || txCount > limit)
|
|
.pb-4.pb-md-3.bg-tx-separator
|
|
|
|
|
|
if (txCount > limit && !options.hidePagination)
|
|
.rounded-0.rounded-bottom.bg-content.border
|
|
.p-3
|
|
if (!crawlerBot && txCount > limit)
|
|
h6.fw-normal.mb-2 #{offset.toLocaleString()} - #{Math.min(offset + limit - 1, txCount - 1).toLocaleString()} of #{txCount.toLocaleString()}
|
|
+pagination(limit, offset, null, txCount, paginationBaseUrl)
|
|
|
|
|
|
mixin pageTabs(names)
|
|
ul.nav.nav-tabs#page-tabs
|
|
each name, nameIndex in names
|
|
li.nav-item.page-tab(style=(nameIndex == 0 ? "margin-left: 10px;" : false))
|
|
a.nav-link(class=(nameIndex == 0 ? "active" : false), data-bs-toggle="tab", data-default-tab=(nameIndex == 0 ? "true" : false) href=`#${name.replace(" ", "-")}`, role="tab") #{name}
|
|
|
|
.bg-gradient-body-to-main.pb-4.mb-2
|
|
|
|
|
|
mixin pillTabs(names)
|
|
ul.nav.nav-pills.mb-3
|
|
each name, nameIndex in names
|
|
li.nav-item
|
|
a.nav-link(class=(nameIndex == 0 ? "active" : false), data-bs-toggle="tab", href=`#${name.replace(" ", "-")}`, role="tab") #{name}
|
|
|
|
|
|
mixin pageTab(name, defaultActive=false)
|
|
div.tab-pane(id=`${name.replace(" ", "-")}`, class=(defaultActive ? "active" : false), role="tabpanel")
|
|
block
|
|
|
|
|
|
mixin valueDisplay(val)
|
|
if (val > 0)
|
|
if (userSettings.displayCurrency == "btc")
|
|
+_valueDisplayBtc(val)
|
|
|
|
else if (userSettings.displayCurrency == "sat")
|
|
+_valueDisplaySat(val, 1000000)
|
|
|
|
else if (userSettings.displayCurrency == "local")
|
|
+_valueDisplayLocal(val, 1000000)
|
|
|
|
else
|
|
span 0
|
|
|
|
|
|
mixin _valueDisplayBtc(val)
|
|
- var parts = utils.formatCurrencyAmount(val, userSettings.displayCurrency);
|
|
|
|
//span #{JSON.stringify(parts)}
|
|
|
|
//span.d-inline.d-sm-none.fw-light.me-tiny ₿
|
|
|
|
span #{parts.val}
|
|
if (parts.lessSignificantDigits)
|
|
span.text-small.text-darken.ms-1 #{parts.lessSignificantDigits}
|
|
|
|
if (exchangeRates)
|
|
- var localCurFormatData = utils.getExchangedCurrencyFormatData(val, userSettings.localCurrency);
|
|
|
|
span.xs-hidden.d-none.d-sm-inline.text-tiny.text-tight-spacing.border-dotted.fw-light.ms-1(data-bs-toggle="tooltip", title=`<span class="me-tiny">${localCurFormatData.symbol}</span><span>${localCurFormatData.value}</span>`, data-bs-html="true") #{parts.currencyUnit}
|
|
|
|
else
|
|
span.xs-hidden.d-none.d-sm-inline.text-tiny.text-tight-spacing.fw-light.ms-1 #{parts.currencyUnit}
|
|
|
|
|
|
mixin _valueDisplaySat(val, summarizeMin=Infinity, summarizeDecimals=3)
|
|
- var parts = utils.formatCurrencyAmount(val, localCurrencyDisplay ? userSettings.localCurrency : userSettings.displayCurrency);
|
|
|
|
//span #{JSON.stringify(parts)}
|
|
|
|
if (parts.intVal >= summarizeMin)
|
|
//span #{JSON.stringify(parts)}
|
|
- var largeNumberData = utils.formatLargeNumberSignificant(parts.intVal, summarizeDecimals >= 0 ? summarizeDecimals : 3);
|
|
//span #{JSON.stringify(largeNumberData)} #{parts.intVal}
|
|
span(title=parts.intVal.toLocaleString(), data-bs-toggle="tooltip") #{largeNumberData[0]}
|
|
span.ms-1 #{largeNumberData[1].textDesc}
|
|
|
|
else
|
|
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{parts.intVal.toLocaleString()}
|
|
|
|
|
|
if (exchangeRates)
|
|
- var localCurFormatData = utils.getExchangedCurrencyFormatData(val, userSettings.localCurrency);
|
|
|
|
span.xs-hidden.d-none.d-sm-inline.text-tiny.text-tight-spacing.border-dotted.fw-light.ms-1(data-bs-toggle="tooltip", title=`<span class="me-tiny">${localCurFormatData.symbol}</span><span>${localCurFormatData.value}</span>`, data-bs-html="true") #{parts.currencyUnit}
|
|
|
|
else
|
|
span.xs-hidden.d-none.d-sm-inline.text-tiny.text-tight-spacing.fw-light.ms-1 #{parts.currencyUnit}
|
|
|
|
|
|
mixin _valueDisplayLocal(val, summarizeMin=Infinity, summarizeDecimals=3)
|
|
- var localCurrencyDisplay = userSettings.displayCurrency == "local";
|
|
|
|
- var parts = utils.formatCurrencyAmount(val, userSettings.localCurrency);
|
|
|
|
//span #{JSON.stringify(parts)}
|
|
span.fw-light.me-tiny #{global.currencySymbols[userSettings.localCurrency]}
|
|
|
|
if (parts.intVal >= summarizeMin)
|
|
- var largeNumberData = utils.formatLargeNumberSignificant(parts.intVal, summarizeDecimals >= 0 ? summarizeDecimals : 3);
|
|
//span #{JSON.stringify(largeNumberData)} #{parts.intVal}
|
|
span.border-dotted(title=`${global.currencySymbols[userSettings.localCurrency]}${parts.intVal.toLocaleString()}<br/>${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC`, data-bs-toggle="tooltip", data-bs-html="true")
|
|
span #{largeNumberData[0]}
|
|
span.ms-1 #{largeNumberData[1].textDesc}
|
|
|
|
else
|
|
span.border-dotted(title=`${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC`, data-bs-toggle="tooltip") #{parts.val}
|
|
|
|
|
|
mixin valueDisplaySpecial(val, maxDecimals=-1, summarizeAlways=false, summarizeMin=Infinity, summarizeDecimals=-1)
|
|
if (maxDecimals == -1 && summarizeAlways == false && summarizeMin == undefined)
|
|
+valueDisplay(val)
|
|
|
|
else
|
|
if (val > 0)
|
|
- var localCurrencyDisplay = userSettings.displayCurrency == "local";
|
|
|
|
if (maxDecimals > 0)
|
|
- var parts = utils.formatCurrencyAmountWithForcedDecimalPlaces(val, localCurrencyDisplay ? userSettings.localCurrency : userSettings.displayCurrency, maxDecimals);
|
|
|
|
else
|
|
- var parts = utils.formatCurrencyAmount(val, localCurrencyDisplay ? userSettings.localCurrency : userSettings.displayCurrency);
|
|
|
|
//span #{JSON.stringify(parts)}
|
|
if (localCurrencyDisplay)
|
|
span.me-1 #{global.currencySymbols[userSettings.localCurrency]}
|
|
//| #{JSON.stringify(parts)}
|
|
|
|
if (summarizeAlways || parts.intVal >= summarizeMin)
|
|
//span #{JSON.stringify(parts)}
|
|
- var largeNumberData = utils.formatLargeNumberSignificant(parts.intVal, summarizeDecimals >= 0 ? summarizeDecimals : 2);
|
|
//span #{JSON.stringify(largeNumberData)} #{parts.intVal}
|
|
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{largeNumberData[0]} #{largeNumberData[1].textDesc}
|
|
|
|
else if (maxDecimals == 0)
|
|
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{parts.intVal.toLocaleString()}
|
|
|
|
else if (maxDecimals > 0)
|
|
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{parts.val}
|
|
|
|
else
|
|
span(class=(localCurrencyDisplay ? "border-dotted" : false), title=(localCurrencyDisplay ? `${utils.formatCurrencyAmount(val, coinConfig.defaultCurrencyUnit.name.toLowerCase()).simpleVal} BTC` : false), data-bs-toggle=(localCurrencyDisplay ? "tooltip" : false)) #{parts.val}
|
|
if (parts.lessSignificantDigits)
|
|
span.text-small.text-muted.ms-1 #{parts.lessSignificantDigits}
|
|
|
|
if (userSettings.displayCurrency != "local")
|
|
if (exchangeRates)
|
|
- var localCurFormatData = utils.getExchangedCurrencyFormatData(val, userSettings.localCurrency);
|
|
|
|
span.text-tiny.text-tight-spacing.border-dotted.fw-light.ms-1(data-bs-toggle="tooltip", title=`<span class="me-tiny">${localCurFormatData.symbol}</span><span>${localCurFormatData.value}</span>`, data-bs-html="true") #{parts.currencyUnit}
|
|
|
|
else
|
|
span.text-tiny.text-tight-spacing.fw-light.ms-1 #{parts.currencyUnit}
|
|
|
|
else if (userSettings.displayCurrency == "local")
|
|
|
|
else
|
|
span 0
|
|
|
|
|
|
mixin confirmations(confirmations, abbreviated=true)
|
|
if (confirmations < 6)
|
|
span.text-warning.border-dotted(title="Fewer than 6 confirmations is generally considered <b>unsettled</b> for high-value transactions because block <b>re-organizations</b> that could affect them have reasonable probability.", data-bs-toggle="tooltip", data-bs-html="true") #{confirmations.toLocaleString()}
|
|
i.fas.fa-unlock-alt.fa-sm.ms-1
|
|
else
|
|
span.border-dotted.text-success(title="6 confirmations is generally considered <b>settled</b>. High-value transactions may require more;<br/>Low-value transactions may require fewer.", data-bs-toggle="tooltip", data-bs-html="true")
|
|
| #{abbreviated && confirmations > 1000 ? `${Math.floor(confirmations/1000)}k` : confirmations.toLocaleString()}
|
|
i.fas.fa-check.ms-1
|
|
|
|
|
|
|
|
mixin cardHighlightBadge(text)
|
|
span.small.badge.bg-card-highlight-badge.border.border-card-highlight-badge.text-reset.mb-tiny.me-1 #{text ? text : ""}
|
|
if (block)
|
|
block
|
|
|
|
|
|
|
|
mixin hexDataDisplay(hex, order="utf8,ascii,hex")
|
|
- var items = order.split(",");
|
|
- var uniqueId = utils.getRandomString(12, "aA");
|
|
|
|
.d-inline-block.small.border.rounded-1.p-1.px-2.card-highlight.word-wrap
|
|
+cardHighlightBadge(items[0])
|
|
span.small #{utils.formatHex(hex, items[0])}
|
|
if (items[0] == "hex")
|
|
.d-none.d-md-inline
|
|
+copyTextButton(hex)
|
|
|
|
div(id=`hex-display-expanded-${uniqueId}`, style="display: none;")
|
|
each item, itemIndex in items
|
|
if (itemIndex > 0)
|
|
if (itemIndex > 1)
|
|
br
|
|
|
|
+cardHighlightBadge(item)
|
|
span.small #{utils.formatHex(hex, item)}
|
|
if (item == "hex")
|
|
.d-inline.d-md-inline
|
|
+copyTextButton(hex)
|
|
|
|
|
|
a.text-muted.ms-2(href="javascript:void(0)", onclick=`$('#hex-display-expanded-${uniqueId}').toggle(); $(this).find(".toggle-plus-minus").toggleClass("fa-plus-square"); $(this).find(".toggle-plus-minus").toggleClass("fa-minus-square"); return false;`, title="Toggle More Encodings")
|
|
i.toggle-plus-minus.far.fa-plus-square.text-card-highlight
|
|
|
|
|
|
|
|
|
|
mixin timestamp(timestamp, includeAgo=true, formatString)
|
|
- var tzDiff = -parseFloat(browserTzOffset);
|
|
|
|
if (userTzOffset != "unset")
|
|
- tzDiff = parseFloat(userTzOffset);
|
|
|
|
- var tzMoment = moment.utc(new Date(parseInt(timestamp) * 1000)).add(tzDiff, "hours");
|
|
- var utcMoment = moment.utc(new Date(parseInt(timestamp) * 1000));
|
|
- var momentObj = (uiTimezone == "utc" ? utcMoment : tzMoment);
|
|
- var nowMoment = (uiTimezone == "utc" ? moment.utc(new Date()) : moment.utc(new Date()).add(tzDiff, "hours"));
|
|
|
|
- var yearStr = momentObj.format("Y");
|
|
- var nowYearStr = nowMoment.format("Y");
|
|
|
|
- var dateStr = momentObj.format("Y-M-D");
|
|
- var nowDateStr = nowMoment.format("Y-M-D");
|
|
|
|
|
|
if (tzDiff != 0 && uiTimezone == "local")
|
|
- var titleStr = `${tzMoment.format("Y-MM-DD, h:mm:ss A")}<br/>(${utcMoment.format("Y-MM-DD, HH:mm:ss")} UTC)`;
|
|
else
|
|
- var titleStr = `${utcMoment.format("Y-MM-DD, HH:mm:ss")} utc`;
|
|
|
|
if (formatString)
|
|
span.border-dotted(title=titleStr, data-bs-toggle="tooltip", data-bs-html="true")
|
|
span.date-text(id=`xyz-${utils.getRandomString(10, "aA1")}`, data-timestamp-utc=`${parseInt(timestamp)}`, data-date-format=formatString, data-date-ago=includeAgo.toString()) #{momentObj.format(formatString)}
|
|
if (["H", "m", "s"].some(str => formatString.includes(str)))
|
|
span.text-tiny.text-tight-spacing.text-muted.ms-tiny UTC
|
|
|
|
else if (dateStr == nowDateStr)
|
|
span.border-dotted(title=titleStr, data-bs-toggle="tooltip", data-bs-html="true")
|
|
if (tzDiff != 0 && uiTimezone == "local")
|
|
span.date-text(id=`xyz-${utils.getRandomString(10, "aA1")}`, data-timestamp-utc=`${parseInt(timestamp)}`, data-date-ago=includeAgo.toString()) #{momentObj.format("h:mm")}
|
|
span.text-tiny.text-tight-spacing.fw-light.ms-tiny #{momentObj.format("A")}
|
|
|
|
else
|
|
span #{momentObj.format("HH:mm")}
|
|
span.text-tiny.text-tight-spacing.fw-light.ms-tiny UTC
|
|
|
|
else if (yearStr == nowYearStr)
|
|
span.border-dotted(title=titleStr, data-bs-toggle="tooltip", data-bs-html="true")
|
|
if (tzDiff != 0 && uiTimezone == "local")
|
|
span.date-text(id=`xyz-${utils.getRandomString(10, "aA1")}`, data-timestamp-utc=`${parseInt(timestamp)}`, data-date-ago=includeAgo.toString()) #{momentObj.format("M/D, h:mm")}
|
|
span.text-tiny.text-tight-spacing.fw-light.ms-tiny #{momentObj.format("A")}
|
|
|
|
else
|
|
span #{momentObj.format("M/D, HH:mm")}
|
|
span.text-tiny.text-tight-spacing.fw-light.ms-tiny UTC
|
|
|
|
else
|
|
span.border-dotted(title=titleStr, data-bs-toggle="tooltip", data-bs-html="true")
|
|
if (tzDiff != 0 && uiTimezone == "local")
|
|
span.date-text(id=`xyz-${utils.getRandomString(10, "aA1")}`, data-timestamp-utc=`${parseInt(timestamp)}`, data-date-ago=includeAgo.toString()) #{momentObj.format("YYYY-MM-DD")}
|
|
|
|
else
|
|
span #{momentObj.format("YYYY-MM-DD")}
|
|
|
|
if (includeAgo)
|
|
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timestamp) * 1000))));
|
|
|
|
if (timeAgo.asSeconds() < 0)
|
|
- timeAgo = moment.duration(moment.utc(new Date(parseInt(timestamp) * 1000)).diff(moment.utc(new Date())));
|
|
|
|
small.text-muted.ms-2 (+
|
|
| #{timeAgo.format()}
|
|
span )
|
|
else
|
|
small.text-muted.ms-2 (
|
|
+timeAgo(timestamp, true)
|
|
span ago)
|
|
|
|
|
|
mixin darkBadge(text)
|
|
span.badge.bg-dark.border.border-dark.me-2 #{text ? text : ""}
|
|
if (block)
|
|
block
|
|
|
|
|
|
mixin lightBadge(text)
|
|
span.badge.bg-light.text-dark.border.me-2 #{text ? text : ""}
|
|
if (block)
|
|
block
|
|
|
|
|
|
mixin successBadge(text)
|
|
span.badge.bg-success.me-2 #{text ? text : ""}
|
|
if (block)
|
|
block
|
|
|
|
|
|
mixin primaryBadge(text, endMargin=true)
|
|
span.badge.bg-primary(class=(endMargin ? "me-2" : false)) #{text ? text : ""}
|
|
if (block)
|
|
block
|
|
|
|
|
|
mixin funAlert(html, text, referenceUrl)
|
|
.alert.alert-primary.shadow-sm.pb-0(role="alert", style="padding-left: 4rem;")
|
|
i.fas.fa-flag.fa-2x.fontawesome-shadow.text-warning.d-inline-block(style="position: absolute; top: 0; left: 0; width: 40px; margin-left: 0.8rem; margin-top: 1.2rem;")
|
|
|
|
h5.mb-2.fw-light #{coinConfig.name} Fun
|
|
|
|
if (html)
|
|
p
|
|
span !{html}
|
|
|
|
if (referenceUrl && referenceUrl.trim().length > 0 && html.indexOf(referenceUrl) == -1)
|
|
span
|
|
a(href=referenceUrl) Read more
|
|
|
|
else if (text)
|
|
p
|
|
span #{text}
|
|
|
|
if (referenceUrl && referenceUrl.trim().length > 0)
|
|
span
|
|
a(href=referenceUrl) Read more
|
|
|
|
else if (block)
|
|
p
|
|
block
|
|
|
|
|
|
mixin funItemIcon
|
|
i.fas.fa-flag.text-warning
|
|
|
|
|
|
mixin timeAgo(timeAgoTime, only1Element=false)
|
|
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timeAgoTime) * 1000))));
|
|
|
|
if (timeAgo.asHours() < 1)
|
|
if (timeAgo.asMinutes() < 1)
|
|
span #{timeAgo.seconds()}s
|
|
else
|
|
span #{timeAgo.minutes()}m
|
|
|
|
else
|
|
if (timeAgo.asHours() >= 1 && timeAgo.asHours() < 24)
|
|
span #{timeAgo.hours()}h
|
|
|
|
if (!only1Element && timeAgo.minutes() > 0)
|
|
span.ms-1 #{timeAgo.minutes()}m
|
|
|
|
else
|
|
if (only1Element)
|
|
span #{utils.shortenTimeDiff(timeAgo.format()).split(/,?\s+/)[0]}
|
|
else
|
|
span #{utils.shortenTimeDiff(timeAgo.format())}
|
|
|
|
|
|
mixin blockCountdown(title, blocksLeft)
|
|
- var countdownId = utils.getRandomString(10, "aA");
|
|
.alert.alert-success
|
|
.d-flex.justify-content-between
|
|
div
|
|
h5.mb-0
|
|
span.me-2 #{title}:
|
|
|
|
span.lead(id=`countdown-time-${countdownId}`)
|
|
| #{blocksLeft.toLocaleString()} block#{blocksLeft > 1 ? "s" : ""}
|
|
|
|
- var secondsToGo = 10 * 60 * blocksLeft;
|
|
- var minutesToGo = secondsToGo / 60;
|
|
- var hoursToGo = minutesToGo / 60;
|
|
- var daysToGo = hoursToGo / 24;
|
|
|
|
span.ms-1 (
|
|
span ~
|
|
if (daysToGo > 2)
|
|
| #{parseInt(daysToGo)} days
|
|
- var hours = 24 * (daysToGo - Math.floor(daysToGo));
|
|
if (hours > 1)
|
|
span.ms-1 #{parseInt(hours)} hour#{parseInt(hours) > 1 ? "s" :""}
|
|
|
|
else if (daysToGo > 1)
|
|
| 1 day
|
|
- var hours = 24 * (daysToGo - Math.floor(daysToGo));
|
|
if (hours > 1)
|
|
span.ms-1 #{parseInt(hours)} hour#{parseInt(hours) > 1 ? "s" :""}
|
|
|
|
else if (hoursToGo > 2)
|
|
| #{parseInt(hoursToGo)} hours
|
|
- var minutes = 60 * (hoursToGo - Math.floor(hoursToGo));
|
|
if (minutes > 1)
|
|
span.ms-1 #{parseInt(minutes)} minute#{parseInt(minutes) > 1 ? "s" :""}
|
|
|
|
else if (hoursToGo >= 1)
|
|
| 1 hour
|
|
- var minutes = 60 * (hoursToGo - Math.floor(hoursToGo));
|
|
if (minutes > 1)
|
|
span.ms-1 #{parseInt(minutes)} minute#{parseInt(minutes) > 1 ? "s" :""}
|
|
|
|
else
|
|
- var minutes = 60 * (hoursToGo - Math.floor(hoursToGo));
|
|
span #{parseInt(minutes)} minute#{parseInt(minutes) > 1 ? "s" :""}
|
|
|
|
span )
|
|
|
|
if (block)
|
|
a.text-body(href="javascript:void(0);", onclick=`$("#countdown-block-${countdownId}").toggle(); $(".countdown-togglers-${countdownId}").toggle();`)
|
|
i.far.fa-plus-square(class=`countdown-togglers-${countdownId}`)
|
|
i.far.fa-minus-square(class=`countdown-togglers-${countdownId}`, style="display: none;")
|
|
|
|
if (block)
|
|
div(id=`countdown-block-${countdownId}`, style="display: none;")
|
|
.mt-2
|
|
block
|
|
|
|
|
|
|
|
|
|
mixin copyTextButton(text)
|
|
small.ms-2
|
|
if (false)
|
|
a(href="javascript:void(0)", title="Copy", data-clipboard-text=text, data-bs-toggle="tooltip", onclick=`copyTextToClipboard("${text}"); $(".icon-copy").toggle(); $(this).find(".icon-copied").toggle(); setTimeout(() => { $(this).find(".icon-copy").toggle(); $(this).find(".icon-copied").toggle(); }, 2000); return false;`)
|
|
i.far.fa-copy.text-info.icon-copy
|
|
i.fas.fa-check.text-success.icon-copied(style="display: none;")
|
|
|
|
a(href="javascript:void(0)", title="Copy", data-clipboard-text=text, data-bs-toggle="tooltip", onclick=`copyTextToClipboard("${text}"); $(this).attr("title", "Copied!").tooltip("_fixTitle").tooltip("show"); $(this).mouseleave(function() { $(this).tooltip("hide"); $(this).attr("data-bs-original-title", "Copy"); });`)
|
|
i.far.fa-copy.text-info
|
|
|
|
|
|
mixin dismissableInfoAlert(userSettingDismissedName, textToShowWhenClosed)
|
|
- var hiddenByEnvVar = (config.site.hideInfoNotes == "true");
|
|
if (!hiddenByEnvVar && (!userSettings.hideInfoNotes || userSettings.hideInfoNotes == "false"))
|
|
if (userSettings[userSettingDismissedName] != "true")
|
|
.alert.alert-primary.alert-dismissible.shadow-sm.mb-4.ps-3.ps-md-7(role="alert")
|
|
i.d-none.d-md-inline.fas.fa-info-circle.fa-lg.d-inline-block(style="position: absolute; top: 0; left: 0; width: 36px; margin-left: 0.4rem; margin-top: 1.3rem;")
|
|
|
|
block
|
|
|
|
a.btn-close(href=`./changeSetting?name=${userSettingDismissedName}&value=true`, aria-label="Close", style="text-decoration: none;", title="Hide this note", data-bs-toggle="tooltip")
|
|
//button.btn-close.text-muted(type="button", data-bs-dismiss="alert", aria-label="Close", title="Hide this note", data-bs-toggle="tooltip")
|
|
|
|
else if (textToShowWhenClosed)
|
|
.alert.alert-primary.shadow-sm.mb-4(role="alert")
|
|
.clearfix
|
|
.float-start
|
|
i.fas.fa-info-circle.fa-lg.me-3
|
|
| #{textToShowWhenClosed}
|
|
|
|
.float-end
|
|
a.text-muted(href=`./changeSetting?name=${userSettingDismissedName}&value=false`, aria-label="Close", style="text-decoration: none;", title="Open this note", data-bs-toggle="tooltip")
|
|
i.far.fa-plus-square.fa-lg
|
|
|
|
|
|
mixin dismissableAlert(userSettingDismissedName, textToShowWhenClosed)
|
|
if (!userSettings.hideInfoNotes || userSettings.hideInfoNotes == "false")
|
|
if (userSettings[userSettingDismissedName] != "true")
|
|
.alert.alert-primary.alert-dismissible.shadow-sm.mb-4(role="alert")
|
|
block
|
|
|
|
a.btn-close(href=`./changeSetting?name=${userSettingDismissedName}&value=true`, aria-label="Close", style="text-decoration: none;", title="Hide this note", data-bs-toggle="tooltip")
|
|
//button.btn-close.text-muted(type="button", data-bs-dismiss="alert", aria-label="Close", title="Hide this note", data-bs-toggle="tooltip")
|
|
|
|
else if (textToShowWhenClosed)
|
|
.alert.alert-primary.shadow-sm.mb-4(role="alert")
|
|
.clearfix
|
|
.float-start
|
|
i.fas.fa-info-circle.fa-lg.me-3
|
|
| #{textToShowWhenClosed}
|
|
|
|
.float-end
|
|
a.text-muted(href=`./changeSetting?name=${userSettingDismissedName}&value=false`, aria-label="Close", style="text-decoration: none;", title="Open this note", data-bs-toggle="tooltip")
|
|
i.far.fa-plus-square.fa-lg
|
|
|
|
|
|
mixin warningAlert
|
|
.alert.alert-warning.shadow-sm.mb-4.ps-3.ps-md-7(role="alert")
|
|
i.d-none.d-md-inline.fas.fa-exclamation-triangle.fa-lg.d-inline-block(style="position: absolute; top: 0; left: 0; width: 36px; margin-left: 0.4rem; margin-top: 1.3rem;")
|
|
|
|
block
|
|
|
|
|
|
mixin numWithMutedDecimals(numString)
|
|
if (numString.indexOf(".") >= 0)
|
|
- var n = numString.substring(0, numString.indexOf("."));
|
|
- var dec = numString.substring(numString.indexOf("."));
|
|
|
|
span #{n}
|
|
small.text-muted #{dec}
|
|
|
|
else
|
|
span #{numString}
|
|
|
|
|
|
mixin blockRangeFilters
|
|
.clearfix
|
|
.float-start.me-4
|
|
div(id="time-range-buttons")
|
|
div.mb-2
|
|
span.border-dotted.text-uppercase.fw-light.text-card-highlight(title="Analyze blocks over the last N days (approximated using average block time).", data-bs-toggle="tooltip") Time Range
|
|
div.btn-group
|
|
a.btn.btn-primary.block-count-btn(href="javascript:void(0)", data-blockCount="144") 1 day
|
|
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="432") 3 day
|
|
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="1008") 7 day
|
|
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="4320") 30 day
|
|
|
|
.float-start.me-4
|
|
div(id="block-selections-buttons")
|
|
div.mb-2
|
|
span.border-dotted.text-uppercase.fw-light.text-card-highlight(title="Choose from a list of pre-configured 'interesting' historical block ranges.", data-bs-toggle="tooltip") Interesting History
|
|
|
|
div.dropdown
|
|
button.btn.btn-outline-primary.dropdown-toggle(type="button", id="preconfigured-dropdown", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Selections
|
|
div.dropdown-menu(aria-labelledby="preconfigured-dropdown")
|
|
a.dropdown-item(href="javascript:void(0)", data-blocks="0-199") First 200 Blocks
|
|
a.dropdown-item(href="javascript:void(0)", data-blocks="209900-210100") First Halving ±100
|
|
a.dropdown-item(href="javascript:void(0)", data-blocks="419900-420100") Second Halving ±100
|
|
a.dropdown-item(href="javascript:void(0)", data-blocks="629900-630100") Third Halving ±100
|
|
a.dropdown-item(href="javascript:void(0)", data-blocks="481724-481924") SegWit Activation ±100
|
|
|
|
.float-start
|
|
div(id="time-range-buttons")
|
|
div.mb-2
|
|
span.border-dotted.text-uppercase.fw-light.text-card-highlight(title="Manually enter a range of blocks to analyze.", data-bs-toggle="tooltip") Custom Block Range
|
|
|
|
form.form-inline.me-3(id="custom-range-form")
|
|
div.input-group
|
|
input.form-control(type="text", id="custom-range-start", placeholder="min height", style="width: 125px;")
|
|
input.form-control(type="text", id="custom-range-end", placeholder="max height", style="width: 125px;")
|
|
|
|
button.btn.btn-primary(type="submit") Go
|
|
|
|
|
|
|
|
mixin pagination(limit, offset, sort, itemCount, baseUrl, justification="start", large=false)
|
|
- var pageNumber = offset / limit + 1;
|
|
- var pageCount = Math.floor(itemCount / limit);
|
|
- if (pageCount * limit < itemCount) {
|
|
- pageCount++;
|
|
- }
|
|
- var paginationUrlFunction = function(x) {
|
|
- return `${baseUrl}?limit=${limit}&offset=${(x - 1) * limit}${sort ? ("&sort=" + sort) : ""}`
|
|
//- return baseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit);
|
|
//- return baseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit + "&sort=" + sort);
|
|
- }
|
|
|
|
- var pageNumbers = [];
|
|
- for (var x = 1; x <= pageCount; x++) {
|
|
- pageNumbers.push(x);
|
|
- }
|
|
|
|
nav(aria-label="Page navigation")
|
|
ul.pagination.flex-wrap.mb-0(class=`justify-content-${justification}`, class=(large ? "pagination-lg" : false))
|
|
li.page-item(class=(pageNumber == 1 ? "disabled" : false))
|
|
a.page-link(href=(pageNumber == 1 ? "javascript:void(0)" : paginationUrlFunction(pageNumber - 1)), aria-label="Previous")
|
|
span(aria-hidden="true") «
|
|
each x, xIndex in pageNumbers
|
|
if (x >= (pageNumber - 4) && x <= (pageNumber + 4) || xIndex == 0 || xIndex == (pageNumbers.length - 1))
|
|
li.page-item(class=(x == pageNumber ? "active" : false))
|
|
a.page-link(href=(paginationUrlFunction(x))) #{x}
|
|
|
|
if (x == 1 && pageNumber > 6)
|
|
li.page-item.disabled
|
|
a.page-link(href="javascript:void(0)") ...
|
|
|
|
else if (x == (pageCount - 1) && pageNumber < (pageCount - 5))
|
|
li.page-item.disabled
|
|
a.page-link(href="javascript:void(0)") ...
|
|
|
|
li.page-item(class=(pageNumber == pageCount ? "disabled" : false))
|
|
a.page-link(href=(pageNumber == pageCount ? "javascript:void(0)" : paginationUrlFunction(pageNumber + 1)), aria-label="Next")
|
|
span(aria-hidden="true") »
|
|
|
|
|
|
mixin graphPageScriptSetup(dateAdapterNeeded=false)
|
|
script(src=`./js/chart.min.js?v=${cacheId}`, integrity="sha384-ovAl4wbIXnEbY76lSb6GrprFBkoYeu4RKYYNMsADThIn2AweWPOyJqoyR/8/kgML")
|
|
|
|
if (dateAdapterNeeded)
|
|
script(src=`./js/moment.min.js?v=${cacheId}`, integrity="sha384-CJyhAlbbRZX14Q8KxKBt0na1ad4KBs9PklAiNk2Efxs9sgimbIZm9kYLJQeNMUfM")
|
|
script(src=`./js/chartjs-adapter-moment.min.js?v=${cacheId}`, integrity="sha384-Z9r2EsEmivx0l8T8TvYoqqGcpO0cCjKbqVXB8tYUa0hIWKtGVl0TmaF263CjS6XR")
|
|
|
|
if (userSettings.uiTheme && userSettings.uiTheme == "dark")
|
|
script.
|
|
Chart.defaults.color='white';
|
|
var gridLineColor = "#1a4280";
|
|
else
|
|
script.
|
|
Chart.defaults.color='black';
|
|
var gridLineColor = "#dddddd";
|
|
|
|
|
|
mixin quote(quote, quoteIndex=-1)
|
|
blockquote.blockquote
|
|
span.fs-4.font-serif "
|
|
|
|
if (quoteIndex >= 0)
|
|
a.fs-5.font-serif.text-reset(href=`./quote/${quoteIndex}`) #{quote.text}
|
|
else
|
|
span.fs-5.font-serif #{quote.text}
|
|
|
|
span.fs-4.font-serif "
|
|
br
|
|
.ms-8.mt-2
|
|
if (quote.speaker.indexOf("https://twitter.com") >= 0)
|
|
- var account = quote.speaker.substring("https://twitter.com/".length);
|
|
| —
|
|
a.fs-5(href=quote.speaker, target="_blank") @#{account}
|
|
|
|
else
|
|
span.fs-5 — #{quote.speaker}
|
|
|
|
if (quote.date)
|
|
small.fw-light , #{quote.date}
|
|
|
|
|
|
if (quote.url)
|
|
small.text-muted.ms-2 (
|
|
a(href=quote.url, target="_blank") ref
|
|
i.fas.fa-external-link-alt.fa-sm.ms-1
|
|
| )
|
|
|
|
if (quote.context)
|
|
div
|
|
i.fs-6.text-muted.ms-2 (#{quote.context})
|