Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,121 @@
|
||||
// Generated, do not edit. sha256:1c9c0ff79637180d3780a7e1dd1e59dbb03533899d9a66468c9cdf709d9ee0fe
|
||||
import { t, localeTag } from '../i18n/index.js';
|
||||
import { listAssets } from '../data/assets.js';
|
||||
import { liveSpotFor, basePriceOf } from '../price/providers.js';
|
||||
import { fmtMoney, fmtInt, currencySymbol, currencyName, parseLocaleNumber } from '../ui/format.js';
|
||||
import { baseCurrency } from '../app-settings.js';
|
||||
|
||||
const TO_BTC = { btc: 1, mbtc: 1e-3, bit: 1e-6, sat: 1e-8, msat: 1e-11 };
|
||||
const UNITS = ['fiat', 'btc', 'mbtc', 'bit', 'sat', 'msat'];
|
||||
|
||||
export const title = () => t('conversion.title');
|
||||
|
||||
const parseNumber = str => parseLocaleNumber(str) || 0;
|
||||
|
||||
function formatUnit(unit, value) {
|
||||
if (value === 0) return '';
|
||||
const nl = localeTag();
|
||||
switch (unit) {
|
||||
case 'fiat': return value.toLocaleString(nl, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
case 'btc': return value.toLocaleString(nl, { maximumFractionDigits: 8 });
|
||||
case 'mbtc': return value.toLocaleString(nl, { maximumFractionDigits: 5 });
|
||||
case 'bit': return value.toLocaleString(nl, { maximumFractionDigits: 2 });
|
||||
case 'sat':
|
||||
case 'msat': return Math.round(value).toLocaleString(nl);
|
||||
}
|
||||
}
|
||||
|
||||
export async function render(el) {
|
||||
const n = fmtInt;
|
||||
el.innerHTML = `
|
||||
|
||||
<div class="card price-hero">
|
||||
<div>
|
||||
<div class="t-label price-label">${t('conversion.btcRate')}</div>
|
||||
<div class="t-value price-val" id="price-display">€ -</div>
|
||||
<div class="price-meta" id="price-meta">${t('conversion.loading')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="conv-grid">
|
||||
${field('fiat', t('conversion.fiat'), '€ EUR', t('conversion.fiatHint'), true)}
|
||||
${field('btc', 'Bitcoin', '₿ BTC', t('conversion.btcHint'))}
|
||||
${field('mbtc', 'Millibitcoin', 'mBTC', `1 BTC = ${n(1e3)} mBTC`)}
|
||||
${field('bit', 'Bit (µBTC)', 'bit', `1 BTC = ${n(1e6)} bits`)}
|
||||
${field('sat', 'Satoshi', 'sat', `1 BTC = ${n(1e8)} sats`)}
|
||||
${field('msat', 'Millisatoshi', 'msat', `1 sat = ${n(1e3)} msats · Lightning`)}
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="t-label info-title">${t('conversion.hierarchy')}</div>
|
||||
<div class="info-body">
|
||||
<strong>1 BTC</strong> = ${n(1e3)} mBTC = ${n(1e6)} bits = ${n(1e8)} sats = ${n(1e11)} msats<br>
|
||||
<strong>1 mBTC</strong> = ${n(1e3)} bits = ${n(1e5)} sats<br>
|
||||
<strong>1 bit</strong> = 100 sats · <strong>1 sat</strong> = ${n(1e3)} msats
|
||||
</div>
|
||||
<div class="info-note">${t('conversion.satNote')}</div>
|
||||
</div>
|
||||
|
||||
<div class="conv-footer">${t('conversion.footer')}</div>`;
|
||||
|
||||
const q = id => el.querySelector('#' + id);
|
||||
const currency = baseCurrency();
|
||||
let livePrice = null;
|
||||
|
||||
function updateAll(sourceUnit, sourceValue) {
|
||||
const rate = livePrice;
|
||||
let btcValue;
|
||||
if (sourceUnit === 'fiat') {
|
||||
if (!rate) return;
|
||||
btcValue = sourceValue / rate;
|
||||
} else {
|
||||
btcValue = sourceValue * TO_BTC[sourceUnit];
|
||||
}
|
||||
UNITS.forEach(unit => {
|
||||
if (unit === sourceUnit) return;
|
||||
const value = unit === 'fiat' ? (rate ? btcValue * rate : 0) : btcValue / TO_BTC[unit];
|
||||
q(unit).value = formatUnit(unit, value);
|
||||
});
|
||||
}
|
||||
function recalcFromFiat() {
|
||||
const f = q('fiat');
|
||||
if (f.value) updateAll('fiat', parseNumber(f.value));
|
||||
}
|
||||
function renderPrice() {
|
||||
const rate = livePrice;
|
||||
q('price-display').textContent = rate ? fmtMoney(rate, currency, { decimals: 0 }) : `${currencySymbol(currency)} -`;
|
||||
}
|
||||
function applyCurrencyUI() {
|
||||
q('fiat-name').textContent = currencyName(currency);
|
||||
q('fiat-badge').textContent = `${currencySymbol(currency)} ${currency}`;
|
||||
renderPrice();
|
||||
recalcFromFiat();
|
||||
}
|
||||
|
||||
UNITS.forEach(unit => q(unit).addEventListener('input', function () {
|
||||
updateAll(unit, parseNumber(this.value));
|
||||
}));
|
||||
applyCurrencyUI();
|
||||
const btc = (await listAssets()).find(a => a.symbol === 'BTC');
|
||||
Promise.resolve(btc ? liveSpotFor(btc) : null).then(p => {
|
||||
if (!p) { q('price-meta').textContent = t('conversion.rateUnavailable'); return; }
|
||||
livePrice = basePriceOf(p);
|
||||
renderPrice(); recalcFromFiat();
|
||||
const now = new Date().toLocaleTimeString(localeTag(), { hour: '2-digit', minute: '2-digit' });
|
||||
q('price-meta').textContent = `${t('conversion.updatedAt')} ${now}`;
|
||||
}).catch(() => { q('price-meta').textContent = t('conversion.rateUnavailable'); });
|
||||
}
|
||||
|
||||
function field(id, name, badge, hint, isFiat = false) {
|
||||
const nameAttr = isFiat ? ' id="fiat-name"' : '';
|
||||
const badgeAttr = isFiat ? ' id="fiat-badge"' : '';
|
||||
return `
|
||||
<label class="field">
|
||||
<div class="field-head">
|
||||
<span class="field-name"${nameAttr}>${name}</span>
|
||||
<span class="badge"${badgeAttr}>${badge}</span>
|
||||
</div>
|
||||
<input type="text" class="field-input" id="${id}" placeholder="0" inputmode="decimal">
|
||||
<span class="field-hint">${hint}</span>
|
||||
</label>`;
|
||||
}
|
||||
Reference in new issue
Block a user