mirror of
https://github.com/kremalicious/blowfish.git
synced 2024-12-28 07:37:51 +01:00
add ticker, add loading state, number formatting
This commit is contained in:
parent
532e8ce7cb
commit
c4d071ddd0
@ -18,8 +18,8 @@
|
||||
"author": "Matthias Kretschmann",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@coingecko/cryptoformat": "^0.3.1",
|
||||
"@oceanprotocol/typographies": "^0.1.0",
|
||||
"crypto-symbols": "^1.0.0",
|
||||
"ms": "^2.1.1",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
13
src/App.css
13
src/App.css
@ -69,7 +69,6 @@ button {
|
||||
cursor: default;
|
||||
height: calc(100vh - 35px);
|
||||
transition: .15s ease-out;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -92,6 +91,7 @@ button {
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
animation: fadein .5s .5s ease-out;
|
||||
}
|
||||
|
||||
.dark .main {
|
||||
@ -137,12 +137,12 @@ button {
|
||||
font-size: 1rem;
|
||||
display: inline-block;
|
||||
padding: 0 .3rem;
|
||||
animation: fadein .5s ease-out forwards;
|
||||
animation: fadeIn .5s ease-out;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.updated {
|
||||
animation: updated .5s ease-out forwards;
|
||||
animation: updated .5s ease-out;
|
||||
}
|
||||
|
||||
.number-unit-wrap--accounts {
|
||||
@ -176,17 +176,12 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
background: rgba(255, 255, 255, .2);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
35
src/App.jsx
35
src/App.jsx
@ -5,7 +5,8 @@ import { Consumer } from './store/createContext'
|
||||
import Titlebar from './components/Titlebar'
|
||||
import Total from './components/Total'
|
||||
import Account from './components/Account'
|
||||
import Actions from './components/Actions'
|
||||
import Ticker from './components/Ticker'
|
||||
import Spinner from './components/Spinner'
|
||||
import './App.css'
|
||||
|
||||
//
|
||||
@ -20,21 +21,27 @@ export default class App extends PureComponent {
|
||||
<AppProvider>
|
||||
<Titlebar />
|
||||
<div className="app__content">
|
||||
<main className="main">
|
||||
<Total />
|
||||
<Consumer>
|
||||
{({ isLoading, accounts }) =>
|
||||
isLoading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<>
|
||||
<main className="main">
|
||||
<Total />
|
||||
|
||||
<div className="number-unit-wrap number-unit-wrap--accounts">
|
||||
<Consumer>
|
||||
{({ accounts }) =>
|
||||
accounts.map((account, i) => (
|
||||
<Account key={i} account={account} />
|
||||
))
|
||||
}
|
||||
</Consumer>
|
||||
</div>
|
||||
<div className="number-unit-wrap number-unit-wrap--accounts">
|
||||
{accounts.map((account, i) => (
|
||||
<Account key={i} account={account} />
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<Actions />
|
||||
</main>
|
||||
<Ticker />
|
||||
</>
|
||||
)
|
||||
}
|
||||
</Consumer>
|
||||
</div>
|
||||
</AppProvider>
|
||||
)
|
||||
|
@ -1,17 +0,0 @@
|
||||
.actions {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
top: -2rem;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
color: #f6388a;
|
||||
font-size: .85rem;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import { Consumer } from '../store/createContext'
|
||||
import './Actions.css'
|
||||
|
||||
export default class Actions extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="actions">
|
||||
<Consumer>
|
||||
{({ toggleCurrencies, accounts }) => (
|
||||
<>
|
||||
{accounts.length > 0 &&
|
||||
Object.keys(accounts[0].balance).map(currency => (
|
||||
<button
|
||||
key={currency}
|
||||
onClick={() => toggleCurrencies(currency)}
|
||||
>
|
||||
{currency}
|
||||
</button>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Consumer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,25 +1,18 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Consumer } from '../store/createContext'
|
||||
import { numberFormatter, fiatFormatter } from '../util/moneyFormatter'
|
||||
import symbols from 'crypto-symbols'
|
||||
import { locale } from '../util/moneyFormatter'
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
|
||||
const Balance = ({ balance }) => (
|
||||
<h1 className="number">
|
||||
<Consumer>
|
||||
{({ currency }) => {
|
||||
const isFiat = currency === 'usd' || currency === 'eur'
|
||||
const symbol =
|
||||
currency === 'ocean' ? 'Ọ' : symbols[currency.toUpperCase()]
|
||||
|
||||
return isFiat ? (
|
||||
fiatFormatter(currency.toUpperCase(), balance[currency])
|
||||
) : (
|
||||
<>
|
||||
{symbol} {numberFormatter(balance[currency]) || 0}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
{({ currency }) =>
|
||||
formatCurrency(balance[currency], currency.toUpperCase(), locale)
|
||||
.replace(/BTC/, 'Ƀ')
|
||||
.replace(/ETH/, 'Ξ')
|
||||
.replace(/OCEAN/, 'Ọ')
|
||||
}
|
||||
</Consumer>
|
||||
</h1>
|
||||
)
|
||||
|
26
src/components/Spinner.css
Normal file
26
src/components/Spinner.css
Normal file
@ -0,0 +1,26 @@
|
||||
.spinner {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner::before {
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: -20px;
|
||||
margin-left: -10px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #7b1173;
|
||||
border-top-color: #e000cf;
|
||||
animation: spinner .6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
5
src/components/Spinner.jsx
Normal file
5
src/components/Spinner.jsx
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
import './Spinner.css'
|
||||
const Spinner = () => <div className="spinner" />
|
||||
|
||||
export default Spinner
|
49
src/components/Ticker.css
Normal file
49
src/components/Ticker.css
Normal file
@ -0,0 +1,49 @@
|
||||
.ticker {
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.ticker .number-unit {
|
||||
flex: initial;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.ticker button {
|
||||
background: none;
|
||||
border: 1px solid #e2e2e2;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
font-size: .8rem;
|
||||
border-radius: .3rem;
|
||||
padding: .2rem .4rem;
|
||||
display: block;
|
||||
transition: border .2s ease-out;
|
||||
}
|
||||
|
||||
.dark .ticker button {
|
||||
border-color: #303030;
|
||||
}
|
||||
|
||||
.ticker button:hover {
|
||||
border-color: #f6388a;
|
||||
color: #f6388a;
|
||||
}
|
||||
|
||||
.ticker button.active,
|
||||
.ticker button.active:hover {
|
||||
border-color: #e2e2e2;
|
||||
background: #f6388a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dark .ticker button.active,
|
||||
.dark .ticker button.active:hover {
|
||||
border-color: #303030;
|
||||
}
|
||||
|
||||
.label--price {
|
||||
display: inline-block;
|
||||
font-size: .95rem;
|
||||
}
|
34
src/components/Ticker.jsx
Normal file
34
src/components/Ticker.jsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import { Consumer } from '../store/createContext'
|
||||
import { userlocale } from '../util/moneyFormatter'
|
||||
import { formatCurrency } from '@coingecko/cryptoformat'
|
||||
import './Ticker.css'
|
||||
|
||||
export default class Ticker extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<footer className="number-unit-wrap ticker">
|
||||
<Consumer>
|
||||
{({ toggleCurrencies, currency, prices }) => (
|
||||
<>
|
||||
{Object.keys(prices).map((key, i) => (
|
||||
<div key={i} className="number-unit">
|
||||
<button
|
||||
className={`label label--price ${key === currency &&
|
||||
'active'}`}
|
||||
onClick={() => toggleCurrencies(key)}
|
||||
>
|
||||
{formatCurrency(prices[key], key.toUpperCase(), userlocale)
|
||||
.replace(/BTC/, 'Ƀ')
|
||||
.replace(/ETH/, 'Ξ')
|
||||
.replace(/OCEAN/, 'Ọ')}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</Consumer>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
}
|
@ -13,8 +13,8 @@ if (
|
||||
isDev = true
|
||||
}
|
||||
|
||||
const width = 550
|
||||
const height = 380
|
||||
const width = 620
|
||||
const height = 440
|
||||
|
||||
const isDarkMode = systemPreferences.isDarkMode()
|
||||
|
||||
@ -30,6 +30,8 @@ const createWindow = async () => {
|
||||
backgroundColor: isDarkMode ? '#141414' : '#fff',
|
||||
frame: false,
|
||||
show: false,
|
||||
title: 'Ocean',
|
||||
scrollBounce: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ export default class AppProvider extends PureComponent {
|
||||
}
|
||||
|
||||
state = {
|
||||
isLoading: true,
|
||||
accounts: [],
|
||||
currency: 'ocean',
|
||||
prices: Object.assign(...prices.map(key => ({ [key]: 0 }))),
|
||||
@ -24,6 +25,7 @@ export default class AppProvider extends PureComponent {
|
||||
async componentDidMount() {
|
||||
await this.fetchAndSetPrices()
|
||||
await this.setBalances()
|
||||
this.setState({ isLoading: false })
|
||||
|
||||
setInterval(this.fetchAndSetPrices, ms(refreshInterval))
|
||||
setInterval(this.setBalances, ms(refreshInterval))
|
||||
@ -72,6 +74,7 @@ export default class AppProvider extends PureComponent {
|
||||
await this.setState({
|
||||
prices: Object.assign(
|
||||
...prices.map(key => ({
|
||||
ocean: 1,
|
||||
[key]: json['ocean-protocol'][key]
|
||||
}))
|
||||
)
|
||||
|
@ -1,18 +1,9 @@
|
||||
const locale = navigator.language
|
||||
export const locale = navigator.language.split('-')[0]
|
||||
// export const locale = 'de'
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
|
||||
const numberFormatter = number =>
|
||||
export const numberFormatter = number =>
|
||||
new Intl.NumberFormat(locale, {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 4
|
||||
}).format(number)
|
||||
|
||||
const fiatFormatter = (currency, number) =>
|
||||
new Intl.NumberFormat(locale, {
|
||||
style: 'currency',
|
||||
currency,
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(number)
|
||||
|
||||
export { numberFormatter, fiatFormatter }
|
||||
|
Loading…
Reference in New Issue
Block a user