From bfe2a76ad68e88626044e9f4215aa44dbffa3686 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Wed, 8 May 2019 01:02:02 +0200 Subject: [PATCH 1/3] setup user preferences --- README.md | 3 - config.js | 1 - package.json | 2 + src/App.css | 127 ++++-------------------------------- src/App.jsx | 48 ++++++-------- src/index.js | 2 +- src/main.js | 2 + src/screens/Home.css | 105 +++++++++++++++++++++++++++++ src/screens/Home.jsx | 41 ++++++++++++ src/screens/Preferences.css | 4 ++ src/screens/Preferences.jsx | 76 +++++++++++++++++++++ src/store/AppProvider.jsx | 49 ++++++++++---- 12 files changed, 301 insertions(+), 159 deletions(-) create mode 100644 src/screens/Home.css create mode 100644 src/screens/Home.jsx create mode 100644 src/screens/Preferences.css create mode 100644 src/screens/Preferences.jsx diff --git a/README.md b/README.md index 7544918..051662d 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,6 @@ Clone, add adresses, and run: git clone git@github.com:kremalicious/ocean-balance.git cd ocean-balance -# Add one or more Ethereum addresses to config file -vi config.js - # Install dependencies npm install # Run the app in dev mode diff --git a/config.js b/config.js index d3a8d46..e6d0825 100644 --- a/config.js +++ b/config.js @@ -1,5 +1,4 @@ module.exports = { - accounts: ['ETH ADDRESS 1', 'ETH ADDRESS 2'], prices: ['eur', 'usd', 'btc', 'eth'], refreshInterval: '1m', oceanTokenContract: '0x985dd3D42De1e256d09e1c10F112bCCB8015AD41' diff --git a/package.json b/package.json index ddda7bb..54f9b24 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "@coingecko/cryptoformat": "^0.3.1", "@oceanprotocol/typographies": "^0.1.0", + "@reach/router": "^1.2.1", "ms": "^2.1.1", "react": "^16.8.6", "react-dom": "^16.8.6" @@ -38,6 +39,7 @@ "electron-devtools-installer": "^2.2.4", "electron-installer-dmg": "^2.0.0", "electron-packager": "^13.1.1", + "electron-store": "^3.2.0", "eslint": "^5.16.0", "eslint-config-prettier": "^4.2.0", "eslint-plugin-react": "^7.13.0", diff --git a/src/App.css b/src/App.css index 07d9ce3..d244c75 100644 --- a/src/App.css +++ b/src/App.css @@ -1,9 +1,16 @@ @import '../node_modules/@oceanprotocol/typographies/css/ocean-typo.css'; +*, +*::before, +*::after { + box-sizing: border-box; +} + html, body { margin: 0; padding: 0; + width: 100%; height: 100%; background: #fcfcfc !important; } @@ -13,12 +20,6 @@ html.dark, background: #141414 !important; } -*, -*::before, -*::after { - box-sizing: border-box; -} - html { font-size: 13px; } @@ -64,11 +65,15 @@ button { font-weight: 600; } -.app__content { +.app { padding: 5% 7%; cursor: default; height: calc(100vh - 35px); transition: .15s ease-out; + width: 100%; +} + +.app > div { display: flex; align-items: center; justify-content: center; @@ -76,112 +81,6 @@ button { width: 100%; } -.fullscreen .app__content { +.fullscreen .app { transform: translate3d(0, -36px, 0); } - -.main { - width: 100%; - padding: 5%; - background: #fff; - border-radius: 5px; - border: .1rem solid #e2e2e2; - min-height: 222px; - display: flex; - align-items: center; - flex-wrap: wrap; - position: relative; - animation: fadein .5s .5s ease-out; -} - -.dark .main { - background: #222; - border-color: #303030; -} - -.number-unit-wrap { - display: flex; - width: 100%; - flex-wrap: wrap; - justify-content: space-around; - position: relative; -} - -.number-unit { - text-align: center; - flex: 1 1 20%; - margin-top: 5%; - padding-left: 2%; - padding-right: 2%; -} - -.label { - color: #8b98a9; - font-size: .85rem; - display: block; - white-space: nowrap; - margin-top: .3rem; - transition: color .2s ease-out; -} - -.number-unit:hover .label { - color: #f6388a; -} - -.number { - margin: 0; - transition: .15s ease-out; - font-weight: 400; - -webkit-app-region: no-drag; - -webkit-user-select: text; - font-size: 1rem; - display: inline-block; - padding: 0 .3rem; - animation: fadeIn .5s ease-out; - border-radius: 4px; -} - -.updated { - animation: updated .5s ease-out; -} - -.number-unit-wrap--accounts { - min-height: 55px; -} - -.number-unit--main { - padding-bottom: 5%; - border-bottom: 1px solid #e2e2e2; -} - -.number-unit--main:hover .label { - color: #8b98a9; -} - -.dark .number-unit--main { - border-bottom-color: #303030; -} - -.number-unit--main .number { - font-size: 2.5rem; -} - -@keyframes updated { - 0% { - background: rgba(255, 255, 255, .2); - } - - 100% { - background: rgba(255, 255, 255, 0); - } -} - -@keyframes fadeIn { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} diff --git a/src/App.jsx b/src/App.jsx index c869b60..d9514c3 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,12 +1,15 @@ import React, { PureComponent } from 'react' +import { + Router, + createMemorySource, + createHistory, + LocationProvider +} from '@reach/router' import { webFrame } from 'electron' import AppProvider from './store/AppProvider' -import { Consumer } from './store/createContext' import Titlebar from './components/Titlebar' -import Total from './components/Total' -import Account from './components/Account' -import Ticker from './components/Ticker' -import Spinner from './components/Spinner' +import Home from './screens/Home' +import Preferences from './screens/Preferences' import './App.css' // @@ -15,35 +18,22 @@ import './App.css' webFrame.setVisualZoomLevelLimits(1, 1) webFrame.setLayoutZoomLevelLimits(0, 0) +// https://github.com/reach/router/issues/25 +const source = createMemorySource('/') +const history = createHistory(source) + export default class App extends PureComponent { render() { return ( -
- - {({ isLoading, accounts }) => ( - <> -
- {isLoading ? ( - - ) : ( - <> - - -
- {accounts.map((account, i) => ( - - ))} -
- - )} -
- - - - )} -
+
+ + + + + +
) diff --git a/src/index.js b/src/index.js index 95f1224..181b021 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ import React from 'react' import { render } from 'react-dom' + import App from './App' document.body.style.backgroundColor = '#141414' @@ -9,5 +10,4 @@ let root = document.createElement('div') root.id = 'root' document.body.appendChild(root) -// Now we can render our application into it render(, document.getElementById('root')) diff --git a/src/main.js b/src/main.js index 5769afd..5f3033e 100644 --- a/src/main.js +++ b/src/main.js @@ -102,6 +102,8 @@ const createWindow = async () => { mainWindow.setSize(width, height, true) }) + switchTheme() + // Load menubar menu items require('./menu.js') } diff --git a/src/screens/Home.css b/src/screens/Home.css new file mode 100644 index 0000000..fbdc43c --- /dev/null +++ b/src/screens/Home.css @@ -0,0 +1,105 @@ +.main { + width: 100%; + padding: 5%; + background: #fff; + border-radius: 5px; + border: .1rem solid #e2e2e2; + min-height: 222px; + display: flex; + align-items: center; + flex-wrap: wrap; + position: relative; + animation: fadein .5s .5s ease-out; +} + +.dark .main { + background: #222; + border-color: #303030; +} + +.number-unit-wrap { + display: flex; + width: 100%; + flex-wrap: wrap; + justify-content: space-around; + position: relative; +} + +.number-unit { + text-align: center; + flex: 1 1 20%; + margin-top: 5%; + padding-left: 2%; + padding-right: 2%; +} + +.label { + color: #8b98a9; + font-size: .85rem; + display: block; + white-space: nowrap; + margin-top: .3rem; + transition: color .2s ease-out; +} + +.number-unit:hover .label { + color: #f6388a; +} + +.number { + margin: 0; + transition: .15s ease-out; + font-weight: 400; + -webkit-app-region: no-drag; + -webkit-user-select: text; + font-size: 1rem; + display: inline-block; + padding: 0 .3rem; + animation: fadeIn .5s ease-out; + border-radius: 4px; +} + +.updated { + animation: updated .5s ease-out; +} + +.number-unit-wrap--accounts { + min-height: 55px; +} + +.number-unit--main { + padding-bottom: 5%; + border-bottom: 1px solid #e2e2e2; +} + +.number-unit--main:hover .label { + color: #8b98a9; +} + +.dark .number-unit--main { + border-bottom-color: #303030; +} + +.number-unit--main .number { + font-size: 2.5rem; +} + +@keyframes updated { + 0% { + background: rgba(255, 255, 255, .2); + } + + 100% { + background: rgba(255, 255, 255, 0); + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} diff --git a/src/screens/Home.jsx b/src/screens/Home.jsx new file mode 100644 index 0000000..a0a631a --- /dev/null +++ b/src/screens/Home.jsx @@ -0,0 +1,41 @@ +import React, { PureComponent } from 'react' +import { Link } from '@reach/router' +import { Consumer } from '../store/createContext' +import Total from '../components/Total' +import Account from '../components/Account' +import Ticker from '../components/Ticker' +import Spinner from '../components/Spinner' +import './Home.css' + +export default class Home extends PureComponent { + render() { + return ( + + {({ isLoading, accounts, needsConfig }) => ( + <> + Settings +
+ {needsConfig ? ( + 'Needs config' + ) : isLoading ? ( + + ) : ( + <> + + +
+ {accounts.map((account, i) => ( + + ))} +
+ + )} +
+ + + + )} +
+ ) + } +} diff --git a/src/screens/Preferences.css b/src/screens/Preferences.css new file mode 100644 index 0000000..46d48f9 --- /dev/null +++ b/src/screens/Preferences.css @@ -0,0 +1,4 @@ +.preferences { + text-align: left; + width: 100%; +} diff --git a/src/screens/Preferences.jsx b/src/screens/Preferences.jsx new file mode 100644 index 0000000..b61dc79 --- /dev/null +++ b/src/screens/Preferences.jsx @@ -0,0 +1,76 @@ +import React, { PureComponent } from 'react' +import { Link } from '@reach/router' +import Store from 'electron-store' +import './Preferences.css' + +export default class Preferences extends PureComponent { + store = new Store() + + state = { accounts: [], input: '' } + + componentDidMount() { + if (this.store.has('accounts')) { + this.setState({ accounts: this.store.get('accounts') }) + } + } + + handleInputChange = e => { + this.setState({ input: e.target.value }) + } + + handleSave = e => { + e.preventDefault() + + if ( + this.state.input !== '' && + !this.state.accounts.includes(this.state.input) // duplication check + ) { + const joined = [...this.state.accounts, this.state.input] + this.store.set('accounts', joined) + this.setState({ accounts: joined }) + } + } + + handleDelete = (e, account) => { + e.preventDefault() + + let array = this.state.accounts + array = array.filter(item => account !== item) + + const index = array.indexOf(account) + if (index > -1) { + array.splice(index, 1) + } + + this.store.set('accounts', array) + this.setState({ accounts: array }) + } + + render() { + return ( +
+ Hello Preferences Close +
+ {this.state.accounts && + this.state.accounts.map(account => ( +
+ {account} + +
+ ))} +
+
+ + +
+
+ ) + } +} diff --git a/src/store/AppProvider.jsx b/src/store/AppProvider.jsx index bbb7464..6bcf4d3 100644 --- a/src/store/AppProvider.jsx +++ b/src/store/AppProvider.jsx @@ -1,41 +1,66 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import ms from 'ms' +import Store from 'electron-store' import { Provider } from './createContext' -import { - accounts, - refreshInterval, - oceanTokenContract, - prices -} from '../../config' +import { refreshInterval, prices, oceanTokenContract } from '../../config' export default class AppProvider extends PureComponent { static propTypes = { children: PropTypes.any.isRequired } + store = new Store() + state = { isLoading: true, accounts: [], currency: 'ocean', + needsConfig: false, prices: Object.assign(...prices.map(key => ({ [key]: 0 }))), toggleCurrencies: currency => this.setState({ currency }) } async componentDidMount() { + const { accountsPref } = await this.getAccounts() await this.fetchAndSetPrices() - await this.setBalances() + await this.setBalances(accountsPref) await setInterval(this.fetchAndSetPrices, ms(refreshInterval)) await setInterval(this.setBalances, ms(refreshInterval)) this.setState({ isLoading: false }) + + // document.addEventListener('DOMContentLoaded', () => { + // this.store.onDidChange('accounts', async (newValue, oldValue) => { + // const { accounts } = await this.getAccounts() + // await this.setBalances(accounts) + + // console.log('hello from setting window', newValue, oldValue) + // }) + // }) } componentWillUnmount() { this.clearAccounts() } + getAccounts() { + let accountsPref + + if (this.store.has('accounts')) { + accountsPref = this.store.get('accounts') + + !accountsPref.length + ? this.setState({ needsConfig: true }) + : this.setState({ needsConfig: false }) + } else { + accountsPref = [] + } + + return { accountsPref } + } + clearAccounts() { this.setState({ accounts: [] }) } @@ -57,7 +82,7 @@ export default class AppProvider extends PureComponent { } } - fetchBalance = async account => { + async fetchBalance(account) { const json = await this.fetch( `https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=${oceanTokenContract}&address=${account}&tag=latest` ) @@ -66,7 +91,7 @@ export default class AppProvider extends PureComponent { return balance } - fetchAndSetPrices = async () => { + async fetchAndSetPrices() { const currencies = prices.join(',') const json = await this.fetch( `https://api.coingecko.com/api/v3/simple/price?ids=ocean-protocol&vs_currencies=${currencies}` @@ -82,12 +107,14 @@ export default class AppProvider extends PureComponent { }) } - setBalances = async () => { + setBalances(accounts) { // TODO: make this less lazy and update numbers in place // when they are changed instead of resetting all to 0 here this.clearAccounts() - accounts.map(async account => { + const accountsArray = accounts ? accounts : this.state.accounts + + accountsArray.map(async account => { const oceanBalance = await this.fetchBalance(account) const conversions = Object.assign( From 67997fe12a5edb590a60d46fb5898b46bf90d77c Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Wed, 8 May 2019 21:41:24 +0200 Subject: [PATCH 2/3] preferences styling --- package.json | 1 + src/components/Balance.jsx | 6 +-- src/components/Ticker.jsx | 6 +-- src/components/Total.jsx | 6 +-- src/screens/Home.jsx | 50 +++++++++++----------- src/screens/Preferences.css | 85 +++++++++++++++++++++++++++++++++++++ src/screens/Preferences.jsx | 67 ++++++++++++++++++++--------- src/store/AppProvider.jsx | 20 ++++----- src/store/createContext.jsx | 4 +- 9 files changed, 176 insertions(+), 69 deletions(-) diff --git a/package.json b/package.json index 54f9b24..988a882 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@reach/router": "^1.2.1", "ms": "^2.1.1", "react": "^16.8.6", + "react-blockies": "^1.4.1", "react-dom": "^16.8.6" }, "devDependencies": { diff --git a/src/components/Balance.jsx b/src/components/Balance.jsx index 229470e..b3741dc 100644 --- a/src/components/Balance.jsx +++ b/src/components/Balance.jsx @@ -1,19 +1,19 @@ import React from 'react' import PropTypes from 'prop-types' -import { Consumer } from '../store/createContext' +import { AppContext } from '../store/createContext' import { locale } from '../util/moneyFormatter' import { formatCurrency } from '@coingecko/cryptoformat' const Balance = ({ balance }) => (

- + {({ currency }) => formatCurrency(balance[currency], currency.toUpperCase(), locale) .replace(/BTC/, 'Ƀ') .replace(/ETH/, 'Ξ') .replace(/OCEAN/, 'Ọ') } - +

) diff --git a/src/components/Ticker.jsx b/src/components/Ticker.jsx index 29bec39..27a00b1 100644 --- a/src/components/Ticker.jsx +++ b/src/components/Ticker.jsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react' -import { Consumer } from '../store/createContext' +import { AppContext } from '../store/createContext' import { locale } from '../util/moneyFormatter' import { formatCurrency } from '@coingecko/cryptoformat' import './Ticker.css' @@ -8,7 +8,7 @@ export default class Ticker extends PureComponent { render() { return (
- + {({ toggleCurrencies, currency, prices }) => ( <> {Object.keys(prices).map((key, i) => ( @@ -27,7 +27,7 @@ export default class Ticker extends PureComponent { ))} )} - +
) } diff --git a/src/components/Total.jsx b/src/components/Total.jsx index c4e4b91..cadd4b8 100644 --- a/src/components/Total.jsx +++ b/src/components/Total.jsx @@ -1,5 +1,5 @@ import React from 'react' -import { Consumer } from '../store/createContext' +import { AppContext } from '../store/createContext' import Balance from './Balance' import { prices } from '../../config' @@ -21,7 +21,7 @@ const calculateTotalBalance = (accounts, currency) => { const Total = () => (
- + {({ accounts }) => { const conversions = Object.assign( ...prices.map(key => ({ @@ -36,7 +36,7 @@ const Total = () => ( return }} - + Total Balance
) diff --git a/src/screens/Home.jsx b/src/screens/Home.jsx index a0a631a..e6eef5d 100644 --- a/src/screens/Home.jsx +++ b/src/screens/Home.jsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react' import { Link } from '@reach/router' -import { Consumer } from '../store/createContext' +import { AppContext } from '../store/createContext' import Total from '../components/Total' import Account from '../components/Account' import Ticker from '../components/Ticker' @@ -8,34 +8,34 @@ import Spinner from '../components/Spinner' import './Home.css' export default class Home extends PureComponent { + static contextType = AppContext + render() { + const { isLoading, accounts, needsConfig } = this.context + return ( - - {({ isLoading, accounts, needsConfig }) => ( - <> - Settings -
- {needsConfig ? ( - 'Needs config' - ) : isLoading ? ( - - ) : ( - <> - + <> + Preferences +
+ {needsConfig ? ( + 'Needs config' + ) : isLoading ? ( + + ) : ( + <> + -
- {accounts.map((account, i) => ( - - ))} -
- - )} -
+
+ {accounts.map((account, i) => ( + + ))} +
+ + )} +
- - - )} -
+ + ) } } diff --git a/src/screens/Preferences.css b/src/screens/Preferences.css index 46d48f9..6852a52 100644 --- a/src/screens/Preferences.css +++ b/src/screens/Preferences.css @@ -2,3 +2,88 @@ text-align: left; width: 100%; } + +.preferences__title { + font-size: 3rem; + margin-top: 0; +} + +.preference__list { + padding: 0; + border-top: 1px solid #e2e2e2; +} + +.dark .preference__list { + border-top-color: #303030; +} + +.preference__list li { + list-style: none; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #e2e2e2; + padding-top: .3rem; + padding-bottom: .25rem; + font-family: monospace; +} + +.dark .preference__list li { + border-bottom-color: #303030; +} + +.preferences button { + background: none; + border: 0; + box-shadow: none; + margin: 0; + outline: 0; + color: #f6388a; + font-size: 1rem; + text-transform: uppercase; +} + +button.delete { + font-size: 2rem; + color: #8b98a9; + transition: color .5s ease-out; +} + +button.delete:hover { + color: #f6388a; +} + +.preference { + -webkit-app-region: none; + -webkit-user-select: text; +} + +.preference__title { + font-size: 1.2rem; + color: #8b98a9; +} + +.preference .identicon { + width: 1.5rem !important; + height: 1.5rem !important; + border-radius: 50%; + vertical-align: middle; + margin-top: -.2rem; + margin-right: .5rem; +} + +.preference__input { + font-size: 1rem; + outline: 0; + background: none; + border: 0; + width: 80%; + color: #303030; + margin-top: .75rem; + margin-bottom: .75rem; + font-family: monospace; +} + +.dark .preference__input { + color: #fff; +} diff --git a/src/screens/Preferences.jsx b/src/screens/Preferences.jsx index b61dc79..0ed896b 100644 --- a/src/screens/Preferences.jsx +++ b/src/screens/Preferences.jsx @@ -1,9 +1,13 @@ import React, { PureComponent } from 'react' import { Link } from '@reach/router' import Store from 'electron-store' +import Blockies from 'react-blockies' import './Preferences.css' +import { AppContext } from '../store/createContext' export default class Preferences extends PureComponent { + static contextType = AppContext + store = new Store() state = { accounts: [], input: '' } @@ -26,8 +30,10 @@ export default class Preferences extends PureComponent { !this.state.accounts.includes(this.state.input) // duplication check ) { const joined = [...this.state.accounts, this.state.input] + this.store.set('accounts', joined) - this.setState({ accounts: joined }) + this.setState({ accounts: joined, input: '' }) + this.context.setBalances(joined) } } @@ -44,32 +50,51 @@ export default class Preferences extends PureComponent { this.store.set('accounts', array) this.setState({ accounts: array }) + this.context.setBalances(array) } render() { return (
- Hello Preferences Close -
- {this.state.accounts && - this.state.accounts.map(account => ( -
- {account} - -
- ))} +

Preferences

{' '} + Close +
+

Accounts

+
    + {this.state.accounts && + this.state.accounts.map(account => ( +
  • +
    + + {account} +
    + + +
  • + ))} +
  • + + +
  • +
-
- - -
) } diff --git a/src/store/AppProvider.jsx b/src/store/AppProvider.jsx index 6bcf4d3..1bbd8d5 100644 --- a/src/store/AppProvider.jsx +++ b/src/store/AppProvider.jsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import ms from 'ms' import Store from 'electron-store' -import { Provider } from './createContext' +import { AppContext } from './createContext' import { refreshInterval, prices, oceanTokenContract } from '../../config' export default class AppProvider extends PureComponent { @@ -18,7 +18,8 @@ export default class AppProvider extends PureComponent { currency: 'ocean', needsConfig: false, prices: Object.assign(...prices.map(key => ({ [key]: 0 }))), - toggleCurrencies: currency => this.setState({ currency }) + toggleCurrencies: currency => this.setState({ currency }), + setBalances: account => this.setBalances(account) } async componentDidMount() { @@ -30,15 +31,6 @@ export default class AppProvider extends PureComponent { await setInterval(this.setBalances, ms(refreshInterval)) this.setState({ isLoading: false }) - - // document.addEventListener('DOMContentLoaded', () => { - // this.store.onDidChange('accounts', async (newValue, oldValue) => { - // const { accounts } = await this.getAccounts() - // await this.setBalances(accounts) - - // console.log('hello from setting window', newValue, oldValue) - // }) - // }) } componentWillUnmount() { @@ -138,6 +130,10 @@ export default class AppProvider extends PureComponent { } render() { - return {this.props.children} + return ( + + {this.props.children} + + ) } } diff --git a/src/store/createContext.jsx b/src/store/createContext.jsx index 25bffa4..75ba03c 100644 --- a/src/store/createContext.jsx +++ b/src/store/createContext.jsx @@ -1,5 +1,5 @@ import { createContext } from 'react' -const { Provider, Consumer } = createContext() +const AppContext = createContext({}) -export { Provider, Consumer } +export { AppContext } From f6b5e134b411f5f04af64cee83f91261177cbcf9 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Thu, 9 May 2019 00:58:05 +0200 Subject: [PATCH 3/3] preferences icon --- package.json | 1 + src/App.css | 6 +++++- src/components/Titlebar.css | 2 +- src/images/cog.svg | 3 +++ src/main.js | 4 ++-- src/screens/Home.css | 17 +++++++++++++++++ src/screens/Home.jsx | 6 +++++- src/screens/Preferences.css | 29 +++++++++++++++++++++++------ src/screens/Preferences.jsx | 4 +++- webpack.common.config.js | 7 ++++++- 10 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 src/images/cog.svg diff --git a/package.json b/package.json index 988a882..a11d765 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@babel/preset-env": "^7.4.4", "@babel/preset-react": "^7.0.0", "@babel/runtime": "^7.4.4", + "@svgr/webpack": "^4.2.0", "babel-eslint": "^10.0.1", "babel-loader": "^8.0.5", "css-loader": "^2.1.1", diff --git a/src/App.css b/src/App.css index d244c75..4bea8b0 100644 --- a/src/App.css +++ b/src/App.css @@ -13,6 +13,7 @@ body { width: 100%; height: 100%; background: #fcfcfc !important; + overflow: hidden; } html.dark, @@ -66,13 +67,16 @@ button { } .app { + margin-top: 35px; padding: 5% 7%; cursor: default; - height: calc(100vh - 35px); + height: 100vh; transition: .15s ease-out; width: 100%; + overflow-y: auto; } +.app, .app > div { display: flex; align-items: center; diff --git a/src/components/Titlebar.css b/src/components/Titlebar.css index 61799cc..9c58888 100644 --- a/src/components/Titlebar.css +++ b/src/components/Titlebar.css @@ -1,5 +1,5 @@ .titlebar { - align-self: flex-start; + position: fixed; width: 100%; height: 35px; line-height: 35px; diff --git a/src/images/cog.svg b/src/images/cog.svg new file mode 100644 index 0000000..43f1806 --- /dev/null +++ b/src/images/cog.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/main.js b/src/main.js index 5f3033e..1684f8f 100644 --- a/src/main.js +++ b/src/main.js @@ -31,9 +31,9 @@ const createWindow = async () => { frame: false, show: false, title: 'Ocean', - scrollBounce: true, webPreferences: { - nodeIntegration: true + nodeIntegration: true, + scrollBounce: true } }) diff --git a/src/screens/Home.css b/src/screens/Home.css index fbdc43c..52001e1 100644 --- a/src/screens/Home.css +++ b/src/screens/Home.css @@ -17,6 +17,23 @@ border-color: #303030; } +.preferences-link { + position: absolute; + right: 5%; + top: 1.5rem; +} + +.preferences-link svg { + fill: #8b98a9; + transition: fill .2s ease-out; + width: 1.25rem; + height: 1.25rem; +} + +.preferences-link:hover svg { + fill: #f6388a; +} + .number-unit-wrap { display: flex; width: 100%; diff --git a/src/screens/Home.jsx b/src/screens/Home.jsx index e6eef5d..b020b3c 100644 --- a/src/screens/Home.jsx +++ b/src/screens/Home.jsx @@ -5,6 +5,7 @@ import Total from '../components/Total' import Account from '../components/Account' import Ticker from '../components/Ticker' import Spinner from '../components/Spinner' +import IconCog from '../images/cog.svg' import './Home.css' export default class Home extends PureComponent { @@ -15,8 +16,11 @@ export default class Home extends PureComponent { return ( <> - Preferences
+ + + + {needsConfig ? ( 'Needs config' ) : isLoading ? ( diff --git a/src/screens/Preferences.css b/src/screens/Preferences.css index 6852a52..6ca0abe 100644 --- a/src/screens/Preferences.css +++ b/src/screens/Preferences.css @@ -1,11 +1,30 @@ .preferences { text-align: left; width: 100%; + margin: 5%; + position: relative; } .preferences__title { - font-size: 3rem; - margin-top: 0; + font-size: 2rem; + margin-top: -1rem; + margin-bottom: 3rem; +} + +.preferences__close { + text-decoration: none; + font-family: 'Sharp Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', + Helvetica, Arial, sans-serif; + font-weight: 600; + font-size: 2.5rem; + position: absolute; + top: -1.5rem; + right: 0; + color: #8b98a9; +} + +.preferences__close:hover { + color: #f6388a; } .preference__list { @@ -25,7 +44,6 @@ border-bottom: 1px solid #e2e2e2; padding-top: .3rem; padding-bottom: .25rem; - font-family: monospace; } .dark .preference__list li { @@ -45,7 +63,7 @@ button.delete { font-size: 2rem; - color: #8b98a9; + color: #41474e; transition: color .5s ease-out; } @@ -59,7 +77,7 @@ button.delete:hover { } .preference__title { - font-size: 1.2rem; + font-size: 1rem; color: #8b98a9; } @@ -81,7 +99,6 @@ button.delete:hover { color: #303030; margin-top: .75rem; margin-bottom: .75rem; - font-family: monospace; } .dark .preference__input { diff --git a/src/screens/Preferences.jsx b/src/screens/Preferences.jsx index 0ed896b..2534d75 100644 --- a/src/screens/Preferences.jsx +++ b/src/screens/Preferences.jsx @@ -57,7 +57,9 @@ export default class Preferences extends PureComponent { return (

Preferences

{' '} - Close + + × +

Accounts

    diff --git a/webpack.common.config.js b/webpack.common.config.js index ffe177e..5216959 100644 --- a/webpack.common.config.js +++ b/webpack.common.config.js @@ -28,7 +28,12 @@ module.exports = { include: defaultInclude }, { - test: /\.(eot|svg|ttf|woff|woff2)$/, + test: /\.svg$/, + use: ['@svgr/webpack'], + include: defaultInclude + }, + { + test: /\.(eot|ttf|woff|woff2)$/, use: ['file-loader?name=font/[name]__[hash:base64:5].[ext]'], include: defaultInclude }