1
0
mirror of https://github.com/kremalicious/blowfish.git synced 2024-12-29 16:17:52 +01:00

add ticker, add loading state, number formatting

This commit is contained in:
Matthias Kretschmann 2019-05-06 23:39:59 +02:00
parent 532e8ce7cb
commit c4d071ddd0
Signed by: m
GPG Key ID: 606EEEF3C479A91F
13 changed files with 158 additions and 97 deletions

View File

@ -18,8 +18,8 @@
"author": "Matthias Kretschmann", "author": "Matthias Kretschmann",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@coingecko/cryptoformat": "^0.3.1",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"crypto-symbols": "^1.0.0",
"ms": "^2.1.1", "ms": "^2.1.1",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6" "react-dom": "^16.8.6"

View File

@ -69,7 +69,6 @@ button {
cursor: default; cursor: default;
height: calc(100vh - 35px); height: calc(100vh - 35px);
transition: .15s ease-out; transition: .15s ease-out;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -92,6 +91,7 @@ button {
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
position: relative; position: relative;
animation: fadein .5s .5s ease-out;
} }
.dark .main { .dark .main {
@ -137,12 +137,12 @@ button {
font-size: 1rem; font-size: 1rem;
display: inline-block; display: inline-block;
padding: 0 .3rem; padding: 0 .3rem;
animation: fadein .5s ease-out forwards; animation: fadeIn .5s ease-out;
border-radius: 4px; border-radius: 4px;
} }
.updated { .updated {
animation: updated .5s ease-out forwards; animation: updated .5s ease-out;
} }
.number-unit-wrap--accounts { .number-unit-wrap--accounts {
@ -176,17 +176,12 @@ button {
} }
} }
@keyframes fadein { @keyframes fadeIn {
0% { 0% {
opacity: 0; opacity: 0;
} }
50% {
background: rgba(255, 255, 255, .2);
}
100% { 100% {
opacity: 1; opacity: 1;
background: rgba(255, 255, 255, 0);
} }
} }

View File

@ -5,7 +5,8 @@ import { Consumer } from './store/createContext'
import Titlebar from './components/Titlebar' import Titlebar from './components/Titlebar'
import Total from './components/Total' import Total from './components/Total'
import Account from './components/Account' import Account from './components/Account'
import Actions from './components/Actions' import Ticker from './components/Ticker'
import Spinner from './components/Spinner'
import './App.css' import './App.css'
// //
@ -20,22 +21,28 @@ export default class App extends PureComponent {
<AppProvider> <AppProvider>
<Titlebar /> <Titlebar />
<div className="app__content"> <div className="app__content">
<Consumer>
{({ isLoading, accounts }) =>
isLoading ? (
<Spinner />
) : (
<>
<main className="main"> <main className="main">
<Total /> <Total />
<div className="number-unit-wrap number-unit-wrap--accounts"> <div className="number-unit-wrap number-unit-wrap--accounts">
<Consumer> {accounts.map((account, i) => (
{({ accounts }) =>
accounts.map((account, i) => (
<Account key={i} account={account} /> <Account key={i} account={account} />
)) ))}
</div>
</main>
<Ticker />
</>
)
} }
</Consumer> </Consumer>
</div> </div>
<Actions />
</main>
</div>
</AppProvider> </AppProvider>
) )
} }

View File

@ -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;
}

View File

@ -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>
)
}
}

View File

@ -1,25 +1,18 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Consumer } from '../store/createContext' import { Consumer } from '../store/createContext'
import { numberFormatter, fiatFormatter } from '../util/moneyFormatter' import { locale } from '../util/moneyFormatter'
import symbols from 'crypto-symbols' import { formatCurrency } from '@coingecko/cryptoformat'
const Balance = ({ balance }) => ( const Balance = ({ balance }) => (
<h1 className="number"> <h1 className="number">
<Consumer> <Consumer>
{({ currency }) => { {({ currency }) =>
const isFiat = currency === 'usd' || currency === 'eur' formatCurrency(balance[currency], currency.toUpperCase(), locale)
const symbol = .replace(/BTC/, 'Ƀ')
currency === 'ocean' ? 'Ọ' : symbols[currency.toUpperCase()] .replace(/ETH/, 'Ξ')
.replace(/OCEAN/, 'Ọ')
return isFiat ? ( }
fiatFormatter(currency.toUpperCase(), balance[currency])
) : (
<>
{symbol} {numberFormatter(balance[currency]) || 0}
</>
)
}}
</Consumer> </Consumer>
</h1> </h1>
) )

View 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);
}
}

View 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
View 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
View 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>
)
}
}

View File

@ -13,8 +13,8 @@ if (
isDev = true isDev = true
} }
const width = 550 const width = 620
const height = 380 const height = 440
const isDarkMode = systemPreferences.isDarkMode() const isDarkMode = systemPreferences.isDarkMode()
@ -30,6 +30,8 @@ const createWindow = async () => {
backgroundColor: isDarkMode ? '#141414' : '#fff', backgroundColor: isDarkMode ? '#141414' : '#fff',
frame: false, frame: false,
show: false, show: false,
title: 'Ocean',
scrollBounce: true,
webPreferences: { webPreferences: {
nodeIntegration: true nodeIntegration: true
} }

View File

@ -15,6 +15,7 @@ export default class AppProvider extends PureComponent {
} }
state = { state = {
isLoading: true,
accounts: [], accounts: [],
currency: 'ocean', currency: 'ocean',
prices: Object.assign(...prices.map(key => ({ [key]: 0 }))), prices: Object.assign(...prices.map(key => ({ [key]: 0 }))),
@ -24,6 +25,7 @@ export default class AppProvider extends PureComponent {
async componentDidMount() { async componentDidMount() {
await this.fetchAndSetPrices() await this.fetchAndSetPrices()
await this.setBalances() await this.setBalances()
this.setState({ isLoading: false })
setInterval(this.fetchAndSetPrices, ms(refreshInterval)) setInterval(this.fetchAndSetPrices, ms(refreshInterval))
setInterval(this.setBalances, ms(refreshInterval)) setInterval(this.setBalances, ms(refreshInterval))
@ -72,6 +74,7 @@ export default class AppProvider extends PureComponent {
await this.setState({ await this.setState({
prices: Object.assign( prices: Object.assign(
...prices.map(key => ({ ...prices.map(key => ({
ocean: 1,
[key]: json['ocean-protocol'][key] [key]: json['ocean-protocol'][key]
})) }))
) )

View File

@ -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 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
const numberFormatter = number => export const numberFormatter = number =>
new Intl.NumberFormat(locale, { new Intl.NumberFormat(locale, {
minimumFractionDigits: 0, minimumFractionDigits: 0,
maximumFractionDigits: 4 maximumFractionDigits: 4
}).format(number) }).format(number)
const fiatFormatter = (currency, number) =>
new Intl.NumberFormat(locale, {
style: 'currency',
currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(number)
export { numberFormatter, fiatFormatter }