mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-12 19:20:46 +02:00
parent
9f9ad26427
commit
89a7ef5af6
@ -12,7 +12,7 @@ This repo hosts the code behind [Bitfeed](https://bits.monospace.live), a live v
|
||||
- [Umbrel](https://getumbrel.com) (coming soon)
|
||||
- [Citadel](https://runcitadel.space/)
|
||||
- [Docker](https://github.com/bitfeed-project/bitfeed/blob/master/DOCKER.md)
|
||||
- [Build from source](https://github.com/bitfeed-project/bitfeed/blob/master/README.md#installing-and-building-bitfeed)
|
||||
- [Build from source](#installing-and-building-bitfeed)
|
||||
|
||||
## Installing and Building Bitfeed
|
||||
|
||||
|
17
client/package-lock.json
generated
17
client/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitfeed-client",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitfeed-client",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.3",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.16.5",
|
||||
"@babel/preset-env": "^7.16.5",
|
||||
@ -31,7 +31,8 @@
|
||||
"sass": "^1.49.0",
|
||||
"sirv-cli": "^1.0.14",
|
||||
"svelte": "^3.44.3",
|
||||
"svelte-preprocess": "^4.10.1"
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
"svelte-select": "^4.4.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@ -4063,6 +4064,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-select": {
|
||||
"version": "4.4.7",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-4.4.7.tgz",
|
||||
"integrity": "sha512-fIf9Z8rPI6F8naHZ9wjXT0Pv5gLyhdHAFkHFJnCfVVfELE8e82uOoF0xEVQP6Kir+b4Q5yOvNAzZ61WbSU6A0A=="
|
||||
},
|
||||
"node_modules/through2": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
||||
@ -7205,6 +7211,11 @@
|
||||
"strip-indent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"svelte-select": {
|
||||
"version": "4.4.7",
|
||||
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-4.4.7.tgz",
|
||||
"integrity": "sha512-fIf9Z8rPI6F8naHZ9wjXT0Pv5gLyhdHAFkHFJnCfVVfELE8e82uOoF0xEVQP6Kir+b4Q5yOvNAzZ61WbSU6A0A=="
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bitfeed-client",
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.3",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
@ -30,6 +30,7 @@
|
||||
"sass": "^1.49.0",
|
||||
"sirv-cli": "^1.0.14",
|
||||
"svelte": "^3.44.3",
|
||||
"svelte-preprocess": "^4.10.1"
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
"svelte-select": "^4.4.7"
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
import Icon from '../components/Icon.svelte'
|
||||
import closeIcon from '../assets/icon/cil-x-circle.svg'
|
||||
import { shortBtcFormat, longBtcFormat, timeFormat, integerFormat } from '../utils/format.js'
|
||||
import { exchangeRates, localCurrency } from '../stores.js'
|
||||
import { exchangeRates, settings } from '../stores.js'
|
||||
import { formatCurrency } from '../utils/fx.js'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -21,10 +21,10 @@
|
||||
|
||||
$: {
|
||||
if (block && block.value) {
|
||||
const rate = $exchangeRates[$localCurrency]
|
||||
const rate = $exchangeRates[$settings.currency]
|
||||
let local
|
||||
if (rate && rate.last) {
|
||||
local = formatCurrency($localCurrency, (block.value/100000000) * rate.last, { compact: true })
|
||||
local = formatCurrency($settings.currency, (block.value/100000000) * rate.last, { compact: true })
|
||||
} else {
|
||||
local = null
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { onMount } from 'svelte'
|
||||
import Overlay from '../components/Overlay.svelte'
|
||||
import TierCard from './sponsor/TierCard.svelte'
|
||||
import SatoshiSlider from './sponsor/SatoshiSlider.svelte'
|
||||
import Pill from '../components/Pill.svelte'
|
||||
import Pill from './util/Pill.svelte'
|
||||
import Icon from '../components/Icon.svelte'
|
||||
import boltIcon from '../assets/icon/cil-bolt-filled.svg'
|
||||
import chainIcon from '../assets/icon/cil-link.svg'
|
||||
|
@ -2,25 +2,49 @@
|
||||
import config from '../config.js'
|
||||
import analytics from '../utils/analytics.js'
|
||||
import SidebarMenuItem from '../components/SidebarMenuItem.svelte'
|
||||
import { settings, nativeAntialias, exchangeRates, localCurrency, haveMessages } from '../stores.js'
|
||||
import { settings, nativeAntialias, exchangeRates, haveMessages } from '../stores.js'
|
||||
import { currencies } from '../utils/fx.js'
|
||||
|
||||
function toggle(setting) {
|
||||
$settings[setting] = !$settings[setting]
|
||||
analytics.trackEvent('settings', setting, $settings[setting] ? 'on' : 'off')
|
||||
if (settingConfig[setting] != null && settingConfig[setting].valueType === 'bool') {
|
||||
onChange(setting, !$settings[setting])
|
||||
}
|
||||
}
|
||||
|
||||
function onChange(setting, value) {
|
||||
$settings[setting] = value
|
||||
analytics.trackEvent('settings', setting, $settings[setting])
|
||||
}
|
||||
|
||||
const currencyOptions = Object.keys(currencies).map(code => {
|
||||
return {
|
||||
value: code,
|
||||
label: `${currencies[code].char} ${currencies[code].name}`,
|
||||
tags: [code, currencies[code].name, ...currencies[code].countries]
|
||||
}
|
||||
})
|
||||
|
||||
let settingConfig = {
|
||||
showNetworkStatus: {
|
||||
label: 'Network Status'
|
||||
label: 'Network Status',
|
||||
valueType: 'bool'
|
||||
},
|
||||
darkMode: {
|
||||
label: 'Dark Mode'
|
||||
label: 'Dark Mode',
|
||||
valueType: 'bool'
|
||||
},
|
||||
currency: {
|
||||
label: 'Fiat Currency',
|
||||
type: 'dropdown',
|
||||
valueType: 'string',
|
||||
options: currencyOptions
|
||||
},
|
||||
vbytes: {
|
||||
label: 'Size by',
|
||||
type: 'pill',
|
||||
falseLabel: 'value',
|
||||
trueLabel: 'vbytes'
|
||||
trueLabel: 'vbytes',
|
||||
valueType: 'bool'
|
||||
},
|
||||
}
|
||||
$: {
|
||||
@ -28,21 +52,24 @@ $: {
|
||||
settingConfig.fancyGraphics = false
|
||||
} else {
|
||||
settingConfig.fancyGraphics = {
|
||||
label: 'Fancy Graphics'
|
||||
label: 'Fancy Graphics',
|
||||
valueType: 'bool'
|
||||
}
|
||||
}
|
||||
if (config.messagesEnabled && $haveMessages) {
|
||||
settingConfig.showMessages = {
|
||||
label: 'Message Bar'
|
||||
label: 'Message Bar',
|
||||
valueType: 'bool'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
const rate = $exchangeRates[$localCurrency]
|
||||
const rate = $exchangeRates[$settings.currency]
|
||||
if (rate && rate.last) {
|
||||
settingConfig.showFX = {
|
||||
label: '₿ Price'
|
||||
label: '₿ Price',
|
||||
valueType: 'bool'
|
||||
}
|
||||
} else {
|
||||
settingConfig.showFX = false
|
||||
@ -58,6 +85,6 @@ function getSettings(setting) {
|
||||
|
||||
{#each Object.keys($settings) as setting (setting) }
|
||||
{#if settingConfig[setting]}
|
||||
<SidebarMenuItem {...getSettings(setting)} active={$settings[setting]} on:click={() => { toggle(setting) }} />
|
||||
<SidebarMenuItem {...getSettings(setting)} value={$settings[setting]} on:click={() => { toggle(setting) }} on:input={(e) => { onChange(setting, e.detail)}} />
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -49,54 +49,22 @@ function showBlock () {
|
||||
top: 20%;
|
||||
left: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: column-reverse;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="sidebar">
|
||||
<SidebarTab open={$sidebarToggle === 'settings'} on:click={() => {settings('settings')}} tooltip="Settings">
|
||||
<span slot="tab" title="Settings">
|
||||
<Icon icon={cogIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<Settings />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
<SidebarTab open={$sidebarToggle === 'legend'} on:click={() => {settings('legend')}} tooltip="Key">
|
||||
<span slot="tab">
|
||||
<Icon icon={infoIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<MempoolLegend />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
<SidebarTab open={$sidebarToggle === 'contact'} on:click={() => {settings('contact')}} tooltip="Contact">
|
||||
<span slot="tab">
|
||||
<Icon icon={atIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<ContactTab />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
<SidebarTab on:click={() => openOverlay('about')} tooltip="About">
|
||||
<span slot="tab">
|
||||
<Icon icon={questionIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
</SidebarTab>
|
||||
{#if $haveSupporters }
|
||||
<SidebarTab on:click={() => openOverlay('supporters')} tooltip="Supporters">
|
||||
<!-- displayed in reverse order, to preserve proper z-index layering -->
|
||||
{#if blockHidden }
|
||||
<SidebarTab on:click={() => showBlock()} tooltip="Show Latest Block">
|
||||
<span slot="tab">
|
||||
<Icon icon={peopleIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
</SidebarTab>
|
||||
{/if}
|
||||
{#if config.donationsEnabled }
|
||||
<SidebarTab on:click={() => openOverlay('donation')} tooltip="Donate">
|
||||
<span slot="tab">
|
||||
<Icon icon={giftIcon} color="var(--bold-a)" />
|
||||
<Icon icon={gridIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<MempoolLegend />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
{/if}
|
||||
{#if config.dev && config.debug}
|
||||
@ -109,14 +77,47 @@ function showBlock () {
|
||||
</div>
|
||||
</SidebarTab>
|
||||
{/if}
|
||||
{#if blockHidden }
|
||||
<SidebarTab on:click={() => showBlock()} tooltip="Show Latest Block">
|
||||
{#if config.donationsEnabled }
|
||||
<SidebarTab on:click={() => openOverlay('donation')} tooltip="Donate">
|
||||
<span slot="tab">
|
||||
<Icon icon={gridIcon} color="var(--bold-a)" />
|
||||
<Icon icon={giftIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<MempoolLegend />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
{/if}
|
||||
{#if $haveSupporters }
|
||||
<SidebarTab on:click={() => openOverlay('supporters')} tooltip="Supporters">
|
||||
<span slot="tab">
|
||||
<Icon icon={peopleIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
</SidebarTab>
|
||||
{/if}
|
||||
<SidebarTab on:click={() => openOverlay('about')} tooltip="About">
|
||||
<span slot="tab">
|
||||
<Icon icon={questionIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
</SidebarTab>
|
||||
<SidebarTab open={$sidebarToggle === 'contact'} on:click={() => {settings('contact')}} tooltip="Contact">
|
||||
<span slot="tab">
|
||||
<Icon icon={atIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<ContactTab />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
<SidebarTab open={$sidebarToggle === 'legend'} on:click={() => {settings('legend')}} tooltip="Key">
|
||||
<span slot="tab">
|
||||
<Icon icon={infoIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<MempoolLegend />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
<SidebarTab open={$sidebarToggle === 'settings'} on:click={() => {settings('settings')}} tooltip="Settings">
|
||||
<span slot="tab" title="Settings">
|
||||
<Icon icon={cogIcon} color="var(--bold-a)" />
|
||||
</span>
|
||||
<div slot="content">
|
||||
<Settings />
|
||||
</div>
|
||||
</SidebarTab>
|
||||
</div>
|
||||
|
@ -1,12 +1,32 @@
|
||||
<script>
|
||||
import Toggle from '../components/Toggle.svelte'
|
||||
import Pill from '../components/Pill.svelte'
|
||||
import Toggle from './util/Toggle.svelte'
|
||||
import Pill from './util/Pill.svelte'
|
||||
import Select from 'svelte-select'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let active = false
|
||||
export let value = false
|
||||
export let type = 'toggle'
|
||||
export let label = ''
|
||||
export let falseLabel
|
||||
export let trueLabel
|
||||
export let options
|
||||
let selectedOption
|
||||
|
||||
$: {
|
||||
if (options && value) {
|
||||
selectedOption = options.find(option => option.value === value)
|
||||
}
|
||||
}
|
||||
|
||||
function filterSelectItems (label, filterText, option) {
|
||||
return [label, ...option.tags].join(' | ').toLowerCase().includes(filterText.toLowerCase())
|
||||
}
|
||||
|
||||
function onSelect (e) {
|
||||
selectedOption = e.detail
|
||||
dispatch('input', selectedOption.value )
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="text/scss">
|
||||
@ -31,15 +51,33 @@ export let trueLabel
|
||||
.label {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.select {
|
||||
width: 240px;
|
||||
flex-shrink: 0;
|
||||
color: var(--palette-a);
|
||||
--inputColor: var(--palette-a);
|
||||
--itemColor: var(--palette-a);
|
||||
--itemHoverColor: var(--palette-a);
|
||||
--borderFocusColor: var(--palette-good);
|
||||
|
||||
:global(.selectContainer) {
|
||||
border-width: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="sidebar-menu-item" class:active={active} on:click>
|
||||
<div class="sidebar-menu-item" class:active={value} on:click>
|
||||
{#if type === 'pill'}
|
||||
<span class="label">{ label }</span>
|
||||
<Pill active={active} left={falseLabel} right={trueLabel} />
|
||||
<Pill active={value} left={falseLabel} right={trueLabel} />
|
||||
{:else if type === 'dropdown'}
|
||||
<div class="select">
|
||||
<Select items={ options } value={selectedOption} isSearchable={true} isClearable={false} itemFilter={filterSelectItems} placeholder={label} on:select={onSelect} showIndicator={true} />
|
||||
</div>
|
||||
{:else}
|
||||
<span class="label">{ label }</span>
|
||||
<Toggle active={active} />
|
||||
<Toggle active={value} />
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ import { fly } from 'svelte/transition'
|
||||
|
||||
export let open = false
|
||||
export let tooltip = null
|
||||
let entered = false
|
||||
|
||||
let contentElement
|
||||
let contentSlotElement
|
||||
@ -20,6 +21,19 @@ async function updateContentHeight (isOpen) {
|
||||
|
||||
$: updateContentHeight(open)
|
||||
|
||||
$: {
|
||||
if (open) setTimeout(afterEnter, 400)
|
||||
else beforeExit()
|
||||
}
|
||||
|
||||
function afterEnter () {
|
||||
entered = true
|
||||
}
|
||||
|
||||
function beforeExit () {
|
||||
entered = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/scss">
|
||||
@ -73,6 +87,12 @@ $: updateContentHeight(open)
|
||||
|
||||
&.open {
|
||||
transform: translateX(-100%);
|
||||
|
||||
&.active {
|
||||
.sidebar-content {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +115,11 @@ $: updateContentHeight(open)
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="sidebar-tab" class:open={open} transition:fly={{ x: 30, duration: 1000 }}>
|
||||
<div
|
||||
class="sidebar-tab"
|
||||
class:open={open}
|
||||
class:active={entered}
|
||||
>
|
||||
<button class="tab-button" on:click title={tooltip}>
|
||||
<slot name="tab">
|
||||
??
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { longBtcFormat, integerFormat } from '../utils/format.js'
|
||||
import { exchangeRates, localCurrency } from '../stores.js'
|
||||
import { exchangeRates, settings } from '../stores.js'
|
||||
import { formatCurrency } from '../utils/fx.js'
|
||||
|
||||
export let tx
|
||||
@ -19,10 +19,10 @@ let formattedLocalValue
|
||||
|
||||
$: {
|
||||
if (tx && tx.value) {
|
||||
const rate = $exchangeRates[$localCurrency]
|
||||
const rate = $exchangeRates[$settings.currency]
|
||||
let local
|
||||
if (rate && rate.last) {
|
||||
formattedLocalValue = formatCurrency($localCurrency, (tx.value/100000000) * rate.last, { compact: true })
|
||||
formattedLocalValue = formatCurrency($settings.currency, (tx.value/100000000) * rate.last, { compact: true })
|
||||
} else {
|
||||
formattedLocalValue = null
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
import SupportersOverlay from '../components/SupportersOverlay.svelte'
|
||||
import Alerts from '../components/alert/Alerts.svelte'
|
||||
import { integerFormat } from '../utils/format.js'
|
||||
import { exchangeRates, localCurrency, lastBlockId, haveSupporters } from '../stores.js'
|
||||
import { exchangeRates, lastBlockId, haveSupporters, sidebarToggle } from '../stores.js'
|
||||
import { formatCurrency } from '../utils/fx.js'
|
||||
import config from '../config.js'
|
||||
|
||||
@ -133,9 +133,9 @@
|
||||
const fxColor = 'good'
|
||||
let fxLabel = ''
|
||||
$: {
|
||||
const rate = $exchangeRates[$localCurrency]
|
||||
const rate = $exchangeRates[$settings.currency]
|
||||
if (rate && rate.last)
|
||||
fxLabel = formatCurrency($localCurrency, rate.last)
|
||||
fxLabel = formatCurrency($settings.currency, rate.last)
|
||||
}
|
||||
|
||||
const debounce = v => {
|
||||
@ -293,6 +293,7 @@
|
||||
.stat-counter, .fx-ticker {
|
||||
margin-top: 5px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
|
||||
&.bad {
|
||||
color: var(--palette-bad);
|
||||
@ -419,7 +420,7 @@
|
||||
<div class="status">
|
||||
<div class="row">
|
||||
{#if $settings.showFX && fxLabel }
|
||||
<span class="fx-ticker {fxColor}">{ fxLabel }</span>
|
||||
<span class="fx-ticker {fxColor}" on:click={() => { $sidebarToggle = 'settings'}}>{ fxLabel }</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -33,6 +33,7 @@ export let rightDisabled = false
|
||||
flex-grow: 1;
|
||||
padding: .5em 1em;
|
||||
background: var(--palette-e);
|
||||
text-align: center;
|
||||
|
||||
&:first-child {
|
||||
border-top-left-radius: .5em;
|
@ -1,5 +1,5 @@
|
||||
function getInjectedEnv (key, fallback) {
|
||||
if (window.injected && window.injected[key] != null) {
|
||||
if (window.injected && window.injected[key] != null && window.injected[key] != "") {
|
||||
return window.injected[key]
|
||||
}
|
||||
return fallback
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { writable, derived } from 'svelte/store'
|
||||
import { makePollStore } from './utils/pollStore.js'
|
||||
import { symbols } from './utils/fx.js'
|
||||
import LocaleCurrency from 'locale-currency'
|
||||
import { currencies } from './utils/fx.js'
|
||||
import config from './config.js'
|
||||
|
||||
function createCounter () {
|
||||
@ -26,7 +26,13 @@ function createCachedDict (namespace, defaultValues) {
|
||||
// load from local storage
|
||||
Object.keys(initial).forEach(field => {
|
||||
const val = localStorage.getItem(`${namespace}-${field}`)
|
||||
if (val != null) initial[field] = JSON.parse(val)
|
||||
if (val != null) {
|
||||
try {
|
||||
initial[field] = JSON.parse(val)
|
||||
} catch (e) {
|
||||
initial[field] = val
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { subscribe, set, update } = writable(initial)
|
||||
@ -89,9 +95,13 @@ export const blockAreaSize = writable(0)
|
||||
|
||||
export const settingsOpen = writable(false)
|
||||
|
||||
let localeCurrencyCode = LocaleCurrency.getCurrency(navigator.language)
|
||||
if (!currencies[localeCurrencyCode]) localeCurrencyCode = 'USD'
|
||||
|
||||
export const settings = createCachedDict('settings', {
|
||||
darkMode: true,
|
||||
showNetworkStatus: true,
|
||||
currency: localeCurrencyCode,
|
||||
showFX: true,
|
||||
vbytes: false,
|
||||
fancyGraphics: true,
|
||||
@ -111,8 +121,3 @@ export const nativeAntialias = writable(false)
|
||||
const newVisitor = !localStorage.getItem('seen-welcome-msg')
|
||||
// export const overlay = writable(newVisitor ? 'about' : null)
|
||||
export const overlay = writable(null)
|
||||
|
||||
let currencyCode = LocaleCurrency.getCurrency(navigator.language)
|
||||
console.log('LOCALE: ', navigator.language, currencyCode)
|
||||
if (!symbols[currencyCode]) currencyCode = 'USD'
|
||||
export const localCurrency = writable(currencyCode)
|
||||
|
@ -1,119 +1,242 @@
|
||||
export const symbols = {
|
||||
export const currencies = {
|
||||
AUD: {
|
||||
char: "AU$",
|
||||
pre: true
|
||||
char: 'AU$',
|
||||
pre: true,
|
||||
name: 'Australian Dollar',
|
||||
countries: [ 'Australia' ],
|
||||
dp: 2,
|
||||
code: 'AUD'
|
||||
},
|
||||
BRL: {
|
||||
char: "R$",
|
||||
pre: true
|
||||
char: 'R$',
|
||||
pre: true,
|
||||
name: 'Brazilian Real',
|
||||
countries: [ 'Brazil' ],
|
||||
dp: 2,
|
||||
code: 'BRL'
|
||||
},
|
||||
CAD: {
|
||||
char: "CA$",
|
||||
pre: true
|
||||
char: 'CA$',
|
||||
pre: true,
|
||||
name: 'Canadian Dollar',
|
||||
countries: [ 'Canada' ],
|
||||
dp: 2,
|
||||
code: 'CAD'
|
||||
},
|
||||
CHF: {
|
||||
char: "fr.",
|
||||
pre: false
|
||||
char: 'fr.',
|
||||
pre: false,
|
||||
name: 'Swiss Franc',
|
||||
countries: [ 'Switzerland' ],
|
||||
dp: 2,
|
||||
code: 'CHF'
|
||||
},
|
||||
CLP: {
|
||||
char: "CLP$",
|
||||
pre: true
|
||||
char: 'CLP$',
|
||||
pre: true,
|
||||
name: 'Chilean Peso',
|
||||
countries: [ 'Chile' ],
|
||||
dp: 2,
|
||||
code: 'CLP'
|
||||
},
|
||||
CNY: {
|
||||
char: "¥",
|
||||
pre: true
|
||||
char: '¥',
|
||||
pre: true,
|
||||
name: 'Chinese Yuan',
|
||||
countries: [ 'China' ],
|
||||
dp: 2,
|
||||
code: 'CNY'
|
||||
},
|
||||
CZK: {
|
||||
char: "Kč",
|
||||
pre: false
|
||||
char: 'Kč',
|
||||
pre: false,
|
||||
name: 'Czech Koruna',
|
||||
countries: [ 'Czechia' ],
|
||||
dp: 2,
|
||||
code: 'CZK'
|
||||
},
|
||||
DKK: {
|
||||
char: "kr.",
|
||||
pre: false
|
||||
char: 'kr.',
|
||||
pre: false,
|
||||
name: 'Danish Krone',
|
||||
countries: [ 'Denmark' ],
|
||||
dp: 2,
|
||||
code: 'DKK'
|
||||
},
|
||||
EUR: {
|
||||
char: "€",
|
||||
pre: true
|
||||
char: '€',
|
||||
pre: true,
|
||||
name: 'Euro',
|
||||
countries: [
|
||||
'European Union', 'Austria',
|
||||
'Belgium', 'Cyprus',
|
||||
'Estonia', 'Finland',
|
||||
'France', 'Germany',
|
||||
'Greece', 'Ireland',
|
||||
'Italy', 'Latvia',
|
||||
'Lithuania', 'Luxembourg',
|
||||
'Malta', 'Netherlands',
|
||||
'Portugal', 'Slovakia',
|
||||
'Slovenia', 'Spain',
|
||||
'Andorra', 'Monaco',
|
||||
'San Marino', 'Vatican City',
|
||||
'Kosovo', 'Montenegro'
|
||||
],
|
||||
dp: 2,
|
||||
code: 'EUR'
|
||||
},
|
||||
GBP: {
|
||||
char: "£",
|
||||
pre: true
|
||||
char: '£',
|
||||
pre: true,
|
||||
name: 'Pound Sterling',
|
||||
countries: [ 'United Kingdom' ],
|
||||
dp: 2,
|
||||
code: 'GBP'
|
||||
},
|
||||
HKD: {
|
||||
char: "HK$",
|
||||
pre: true
|
||||
char: 'HK$',
|
||||
pre: true,
|
||||
name: 'Hong Kong Dollar',
|
||||
countries: [ 'Hong Kong' ],
|
||||
dp: 2,
|
||||
code: 'HKD'
|
||||
},
|
||||
HRK: {
|
||||
char: "kn",
|
||||
pre: false
|
||||
char: 'kn',
|
||||
pre: false,
|
||||
name: 'Croatian Kuna',
|
||||
countries: [ 'Croatia' ],
|
||||
dp: 2,
|
||||
code: 'HRK'
|
||||
},
|
||||
HUF: {
|
||||
char: "Ft",
|
||||
pre: false
|
||||
char: 'Ft',
|
||||
pre: false,
|
||||
name: 'Hungarian Forint',
|
||||
countries: [ 'Hungary' ],
|
||||
dp: 2,
|
||||
code: 'HUF'
|
||||
},
|
||||
INR: {
|
||||
char: "₹",
|
||||
pre: true
|
||||
char: '₹',
|
||||
pre: true,
|
||||
name: 'Indian Rupee',
|
||||
countries: [ 'India', 'Bhutan' ],
|
||||
dp: 2,
|
||||
code: 'INR'
|
||||
},
|
||||
ISK: {
|
||||
char: "kr",
|
||||
pre: false
|
||||
char: 'kr',
|
||||
pre: false,
|
||||
name: 'Icelandic Króna',
|
||||
countries: [ 'Iceland' ],
|
||||
dp: 2,
|
||||
code: 'ISK'
|
||||
},
|
||||
JPY: {
|
||||
char: "¥",
|
||||
pre: true
|
||||
char: '¥',
|
||||
pre: true,
|
||||
name: 'Japanese Yen',
|
||||
countries: [ 'Japan' ],
|
||||
dp: 2,
|
||||
code: 'JPY'
|
||||
},
|
||||
KRW: {
|
||||
char: "₩",
|
||||
pre: true
|
||||
char: '₩',
|
||||
pre: true,
|
||||
name: 'Korean Won',
|
||||
countries: [ 'South Korea' ],
|
||||
dp: 2,
|
||||
code: 'KRW'
|
||||
},
|
||||
NZD: {
|
||||
char: "NZ$",
|
||||
pre: true
|
||||
char: 'NZ$',
|
||||
pre: true,
|
||||
name: 'New Zealand Dollar',
|
||||
countries: [ 'New Zealand' ],
|
||||
dp: 2,
|
||||
code: 'NZD'
|
||||
},
|
||||
PLN: {
|
||||
char: "zł",
|
||||
pre: false
|
||||
char: 'zł',
|
||||
pre: false,
|
||||
name: 'Polish Złoty',
|
||||
countries: [ 'Poland' ],
|
||||
dp: 2,
|
||||
code: 'PLN'
|
||||
},
|
||||
RON: {
|
||||
char: "L",
|
||||
pre: false
|
||||
char: 'L',
|
||||
pre: false,
|
||||
name: 'Romanian Leu',
|
||||
countries: [ 'Romania' ],
|
||||
dp: 2,
|
||||
code: 'RON'
|
||||
},
|
||||
RUB: {
|
||||
char: "₽",
|
||||
pre: false
|
||||
char: '₽',
|
||||
pre: false,
|
||||
name: 'Russian Ruble',
|
||||
countries: [ 'Russia' ],
|
||||
dp: 2,
|
||||
code: 'RUB'
|
||||
},
|
||||
SEK: {
|
||||
char: "kr",
|
||||
pre: false
|
||||
char: 'kr',
|
||||
pre: false,
|
||||
name: 'Swedish Krona',
|
||||
countries: [ 'Sweden' ],
|
||||
dp: 2,
|
||||
code: 'SEK'
|
||||
},
|
||||
SGD: {
|
||||
char: "S$",
|
||||
pre: true
|
||||
char: 'S$',
|
||||
pre: true,
|
||||
name: 'Singapore Dollar',
|
||||
countries: [ 'Singapore' ],
|
||||
dp: 2,
|
||||
code: 'SGD'
|
||||
},
|
||||
THB: {
|
||||
char: "฿",
|
||||
pre: true
|
||||
char: '฿',
|
||||
pre: true,
|
||||
name: 'Thai Baht',
|
||||
countries: [ 'Thailand' ],
|
||||
dp: 2,
|
||||
code: 'THB'
|
||||
},
|
||||
TRY: {
|
||||
char: "₺",
|
||||
pre: true
|
||||
char: '₺',
|
||||
pre: true,
|
||||
name: 'Turkish Lira',
|
||||
countries: [ 'Turkey' ],
|
||||
dp: 2,
|
||||
code: 'TRY'
|
||||
},
|
||||
TWD: {
|
||||
char: "圓",
|
||||
pre: true
|
||||
char: '圓',
|
||||
pre: true,
|
||||
name: 'New Taiwan Dollar',
|
||||
countries: [ 'Taiwan' ],
|
||||
dp: 2,
|
||||
code: 'TWD'
|
||||
},
|
||||
USD: {
|
||||
char: "$",
|
||||
pre: true
|
||||
char: '$',
|
||||
pre: true,
|
||||
name: 'US Dollar',
|
||||
countries: [ 'United States', 'USA' ],
|
||||
dp: 2,
|
||||
code: 'USD'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function formatCurrency (code, amount, params) {
|
||||
// Support for Intl.NumberFormat not quite there yet for all currencies/locales
|
||||
// const format = new Intl.NumberFormat(currency.locale, {currency: currency.code, currencyDisplay: "symbol", style: "currency"})
|
||||
// return format.format(amount)
|
||||
const currency = symbols[code] || symbols.USD
|
||||
const currency = currencies[code] || currencies.USD
|
||||
let parts = [currency.char]
|
||||
if (params && params.compact) {
|
||||
let compacted = amount
|
||||
@ -129,7 +252,7 @@ export function formatCurrency (code, amount, params) {
|
||||
const amountPart = amount < 1000 ? amount.toPrecision(precision) : Math.round(amount)
|
||||
parts.push(`${amountPart}${['','K','M','B','T'][suffixIndex]}`)
|
||||
} else {
|
||||
parts.push(amount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }))
|
||||
parts.push(amount.toLocaleString(undefined, { minimumFractionDigits: currency.dp, maximumFractionDigits: currency.dp }))
|
||||
}
|
||||
if (!currency.pre) parts = parts.reverse()
|
||||
return parts.join(' ')
|
||||
|
@ -4,7 +4,7 @@ defmodule BitcoinStream.MixProject do
|
||||
def project do
|
||||
[
|
||||
app: :bitcoin_stream,
|
||||
version: "2.1.2",
|
||||
version: "2.1.3",
|
||||
elixir: "~> 1.10",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps(),
|
||||
|
Loading…
Reference in New Issue
Block a user