move renderer to Next.js
14
.babelrc
@ -1,14 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}
|
||||
],
|
||||
"@babel/react"
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
2
.gitignore
vendored
@ -4,3 +4,5 @@ package-lock.json
|
||||
build
|
||||
dist
|
||||
coverage
|
||||
.next
|
||||
out
|
35
package.json
@ -5,13 +5,13 @@
|
||||
"description": "🐡 Simple Electron-based desktop app to retrieve and display your total Ocean Token balances.",
|
||||
"main": "./src/main/index.js",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"test": "npm run lint && jest",
|
||||
"test:watch": "jest --watch",
|
||||
"lint": "eslint --ignore-path .gitignore ./src/**/*.{js,jsx} && stylelint --ignore-path .gitignore ./src/**/*.{css,scss}",
|
||||
"start": "webpack-dev-server --hot --host 0.0.0.0 --config=./webpack.dev.config.js",
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack.common.config.js",
|
||||
"package": "electron-builder build -ml -p never",
|
||||
"package:win": "electron-builder build -w -p never",
|
||||
"build:react": "next build src/renderer && next export src/renderer",
|
||||
"build:electron": "electron-builder build -ml -p never",
|
||||
"build:electron:win": "electron-builder build -w -p never",
|
||||
"dist": "./scripts/release-prepare.sh",
|
||||
"release": "release-it --non-interactive",
|
||||
"changelog": "auto-changelog -p",
|
||||
@ -30,15 +30,13 @@
|
||||
"@coingecko/cryptoformat": "^0.3.3",
|
||||
"ethereum-address": "^0.0.4",
|
||||
"ethereum-blockies": "github:MyEtherWallet/blockies",
|
||||
"ms": "^2.1.2"
|
||||
"ms": "^2.1.2",
|
||||
"shortid": "^2.2.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/preset-env": "^7.8.4",
|
||||
"@babel/preset-react": "^7.8.3",
|
||||
"@jest-runner/electron": "^2.0.3",
|
||||
"@reach/router": "^1.3.1",
|
||||
"@react-mock/state": "^0.1.8",
|
||||
"@svgr/webpack": "^5.0.0",
|
||||
"@testing-library/jest-dom": "^5.0.0",
|
||||
@ -46,42 +44,35 @@
|
||||
"auto-changelog": "^1.16.2",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^25.1.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"cross-env": "^7.0.0",
|
||||
"css-loader": "^3.4.2",
|
||||
"electron": "^8.0.0",
|
||||
"electron-builder": "^22.3.2",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"electron-is-dev": "^1.1.0",
|
||||
"electron-next": "^3.1.5",
|
||||
"electron-store": "^5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.10.0",
|
||||
"eslint-plugin-react": "^7.18.3",
|
||||
"file-loader": "^5.0.2",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^25.1.0",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"next": "^9.2.1",
|
||||
"prettier": "^1.19.1",
|
||||
"prettier-stylelint": "^0.4.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-pose": "^4.0.10",
|
||||
"release-it": "^12.4.3",
|
||||
"style-loader": "^1.1.3",
|
||||
"stylelint": "^13.1.0",
|
||||
"stylelint-config-css-modules": "^2.1.0",
|
||||
"stylelint-config-standard": "^19.0.0",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-dev-server": "^3.10.3"
|
||||
"stylelint-config-standard": "^19.0.0"
|
||||
},
|
||||
"browserslist": "electron >= 6.0",
|
||||
"browserslist": "electron >= 8.0",
|
||||
"build": {
|
||||
"asar": true,
|
||||
"appId": "com.kremalicious.blowfish",
|
||||
"files": [
|
||||
"./build/**/*",
|
||||
"./src/main/**/*",
|
||||
"./src/renderer/out/**/*",
|
||||
"./src/*.js",
|
||||
"package.json"
|
||||
],
|
||||
|
@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf {dist,build}/ && \
|
||||
npm run build && \
|
||||
npm run package && \
|
||||
rm -rf {dist,src/renderer/.next,src/renderer/out}/ && \
|
||||
npm run build:react && \
|
||||
npm run build:electron && \
|
||||
|
||||
if [ -x "$(command -v docker)" ]; then
|
||||
docker run --rm \
|
||||
@ -14,6 +14,6 @@ if [ -x "$(command -v docker)" ]; then
|
||||
-v ~/.cache/electron:/root/.cache/electron \
|
||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||
electronuserland/builder:wine \
|
||||
/bin/bash -c "npm i && npm run build && npm run package:win"
|
||||
/bin/bash -c "npm i && npm run build && npm run build:electron:win"
|
||||
fi
|
||||
|
||||
|
@ -6,6 +6,8 @@ const {
|
||||
nativeTheme,
|
||||
ipcMain
|
||||
} = require('electron')
|
||||
const prepareNext = require('electron-next')
|
||||
const isDev = require('electron-is-dev')
|
||||
const pkg = require('../../package.json')
|
||||
const buildMenu = require('./menu')
|
||||
const { buildTouchbar, updateTouchbar } = require('./touchbar')
|
||||
@ -13,16 +15,6 @@ const { rgbaToHex } = require('../utils')
|
||||
|
||||
let mainWindow
|
||||
|
||||
// Keep a reference for dev mode
|
||||
let isDev = false
|
||||
if (
|
||||
process.defaultApp ||
|
||||
/[\\/]electron-prebuilt[\\/]/.test(process.execPath) ||
|
||||
/[\\/]electron[\\/]/.test(process.execPath)
|
||||
) {
|
||||
isDev = true
|
||||
}
|
||||
|
||||
const width = 640
|
||||
const height = 450
|
||||
|
||||
@ -46,13 +38,14 @@ const createWindow = async () => {
|
||||
nodeIntegration: true,
|
||||
scrollBounce: true,
|
||||
enableBlinkFeatures: 'OverlayScrollbars'
|
||||
// preload: path.join(__dirname, 'preload.js')
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.loadURL(
|
||||
isDev
|
||||
? 'http://localhost:8080'
|
||||
: `file://${path.join(__dirname, '../../build/index.html')}`
|
||||
? 'http://localhost:8000'
|
||||
: `file://${path.join(__dirname, '../renderer/out/index.html')}`
|
||||
)
|
||||
|
||||
createWindowEvents(mainWindow)
|
||||
@ -85,7 +78,9 @@ const createWindow = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
app.on('ready', () => {
|
||||
app.on('ready', async () => {
|
||||
await prepareNext('./src/renderer')
|
||||
|
||||
createWindow()
|
||||
|
||||
mainWindow.webContents.on('dom-ready', () => {
|
||||
@ -138,22 +133,22 @@ const installDevTools = async mainWindow => {
|
||||
const createWindowEvents = mainWindow => {
|
||||
mainWindow.on('enter-full-screen', () =>
|
||||
mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.add(\'fullscreen\')'
|
||||
'document.getElementsByTagName("html")[0].classList.add("fullscreen")'
|
||||
)
|
||||
)
|
||||
mainWindow.on('leave-full-screen', () =>
|
||||
mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.remove(\'fullscreen\')'
|
||||
'document.getElementsByTagName("html")[0].classList.remove("fullscreen")'
|
||||
)
|
||||
)
|
||||
mainWindow.on('blur', () =>
|
||||
mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.add(\'blur\')'
|
||||
'document.getElementsByTagName("html")[0].classList.add("blur")'
|
||||
)
|
||||
)
|
||||
mainWindow.on('focus', () =>
|
||||
mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.remove(\'blur\')'
|
||||
'document.getElementsByTagName("html")[0].classList.remove("blur")'
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -197,10 +192,10 @@ const switchTheme = () => {
|
||||
|
||||
isDarkMode
|
||||
? mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.add(\'dark\')'
|
||||
'document.getElementsByTagName("html")[0].classList.add("dark")'
|
||||
)
|
||||
: mainWindow.webContents.executeJavaScript(
|
||||
'document.getElementsByTagName(\'html\')[0].classList.remove(\'dark\')'
|
||||
'document.getElementsByTagName("html")[0].classList.remove("dark")'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
12
src/main/preload.js
Normal file
@ -0,0 +1,12 @@
|
||||
const { webFrame, ipcRenderer } = require('electron')
|
||||
const Store = require('electron-store')
|
||||
|
||||
const store = new Store()
|
||||
|
||||
// Since we disabled nodeIntegration we can reintroduce
|
||||
// needed node functionality here
|
||||
process.once('loaded', () => {
|
||||
global.ipcRenderer = ipcRenderer
|
||||
global.webFrame = webFrame
|
||||
global.store = store
|
||||
})
|
@ -1,65 +0,0 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
Router,
|
||||
createMemorySource,
|
||||
createHistory,
|
||||
LocationProvider,
|
||||
navigate
|
||||
} from '@reach/router'
|
||||
import { webFrame, ipcRenderer } from 'electron'
|
||||
import posed, { PoseGroup } from 'react-pose'
|
||||
import Titlebar from './components/Titlebar'
|
||||
import { defaultAnimation } from './components/Animations'
|
||||
import Home from './screens/Home'
|
||||
import Preferences from './screens/Preferences'
|
||||
import styles from './App.module.css'
|
||||
|
||||
//
|
||||
// Disable zooming
|
||||
//
|
||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
webFrame.setLayoutZoomLevelLimits(0, 0)
|
||||
|
||||
const Animation = posed.div(defaultAnimation)
|
||||
|
||||
// Fix reach-router in packaged Electron
|
||||
// https://github.com/reach/router/issues/25#issuecomment-394003652
|
||||
let source = createMemorySource('/')
|
||||
let history = createHistory(source)
|
||||
|
||||
const PosedRouter = ({ children }) => (
|
||||
<LocationProvider history={history}>
|
||||
{({ location }) => (
|
||||
<PoseGroup animateOnMount>
|
||||
<Animation key={location.key}>
|
||||
<Router location={location}>{children}</Router>
|
||||
</Animation>
|
||||
</PoseGroup>
|
||||
)}
|
||||
</LocationProvider>
|
||||
)
|
||||
|
||||
PosedRouter.propTypes = {
|
||||
children: PropTypes.any.isRequired
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on('goTo', (evt, route) => {
|
||||
navigate(route)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{process.platform === 'darwin' && <Titlebar />}
|
||||
<div className={styles.app}>
|
||||
<PosedRouter>
|
||||
<Home path="/" default />
|
||||
<Preferences path="/preferences" />
|
||||
</PosedRouter>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
16
src/renderer/babel.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
const { devDependencies } = require('../../package.json')
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'next/babel',
|
||||
{
|
||||
'preset-env': {
|
||||
targets: {
|
||||
electron: devDependencies.electron.replace(/^\^|~/, '')
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
import AppProvider from './store/AppProvider'
|
||||
import App from './App'
|
||||
import pkg from '../../package.json'
|
||||
import './index.css'
|
||||
|
||||
document.body.style.backgroundColor = '#141414'
|
||||
|
||||
// Since we are using HtmlWebpackPlugin WITHOUT a template, we should create our own root node in the body element before rendering into it
|
||||
let root = document.createElement('div')
|
||||
root.id = 'root'
|
||||
document.body.appendChild(root)
|
||||
document.title = pkg.productName
|
||||
|
||||
render(
|
||||
<AppProvider>
|
||||
<App />
|
||||
</AppProvider>,
|
||||
document.getElementById('root')
|
||||
)
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { render } from '@testing-library/react'
|
||||
import AppProvider from './store/AppProvider'
|
||||
import AppProvider from '../store/AppProvider'
|
||||
import App from './App'
|
||||
|
||||
describe('App', () => {
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from '@testing-library/react'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import context from '../../jest/__fixtures__/context'
|
||||
import { AppContext } from '../store/createContext'
|
||||
import context from './__fixtures__/context'
|
||||
import Home from '.'
|
||||
|
||||
describe('Home', () => {
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import { render } from '@testing-library/react'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import { AppContext } from '../store/createContext'
|
||||
import Preferences from '.'
|
||||
|
||||
describe('Preferences', () => {
|
41
src/renderer/next.config.js
Normal file
@ -0,0 +1,41 @@
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const withSvgr = (nextConfig = {}, nextComposePlugins = {}) => {
|
||||
return Object.assign({}, nextConfig, {
|
||||
webpack(config, options) {
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
icon: true
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
if (typeof nextConfig.webpack === 'function') {
|
||||
return nextConfig.webpack(config, options)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = withSvgr({
|
||||
webpack: config => {
|
||||
config.target = 'electron-renderer'
|
||||
|
||||
return config
|
||||
}
|
||||
// exportPathMap() {
|
||||
// // Let Next.js know where to find the entry page
|
||||
// // when it's exporting the static bundle for the use
|
||||
// // in the production version of your app
|
||||
// return {
|
||||
// '/': { page: '/' },
|
||||
// '/preferences': { page: '/preferences' }
|
||||
// }
|
||||
// }
|
||||
})
|
@ -1,5 +0,0 @@
|
||||
.accounts {
|
||||
composes: balanceWrap from './index.module.css';
|
||||
min-height: 55px;
|
||||
padding-top: 2rem;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import React from 'react'
|
||||
import { Link } from '@reach/router'
|
||||
import Accounts from './Accounts'
|
||||
import styles from './index.module.css'
|
||||
|
||||
const Preferences = () => (
|
||||
<div className={styles.preferences}>
|
||||
<h1 className={styles.title}>Preferences</h1>{' '}
|
||||
<Link className={styles.close} title="Close Preferences" to="/">
|
||||
×
|
||||
</Link>
|
||||
<Accounts />
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Preferences
|
27
src/renderer/src/Layout.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import posed, { PoseGroup } from 'react-pose'
|
||||
import shortid from 'shortid'
|
||||
import AppProvider from './store/AppProvider'
|
||||
import { defaultAnimation } from './components/Animations'
|
||||
import Titlebar from './components/Titlebar'
|
||||
import styles from './Layout.module.css'
|
||||
|
||||
const Animation = posed.div(defaultAnimation)
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<AppProvider>
|
||||
{process.platform === 'darwin' && <Titlebar />}
|
||||
<div className={styles.app}>
|
||||
<PoseGroup animateOnMount>
|
||||
<Animation key={shortid.generate()}>{children}</Animation>
|
||||
</PoseGroup>
|
||||
</div>
|
||||
</AppProvider>
|
||||
)
|
||||
}
|
||||
|
||||
Layout.propTypes = {
|
||||
children: PropTypes.any.isRequired
|
||||
}
|
@ -2,7 +2,7 @@ import React, { useContext } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import posed, { PoseGroup } from 'react-pose'
|
||||
import { AppContext } from '../store/createContext'
|
||||
import { cryptoFormatter } from '../../utils'
|
||||
import { cryptoFormatter } from '../../../utils'
|
||||
import { fadeIn } from './Animations'
|
||||
import Label from './Label'
|
||||
import styles from './Balance.module.css'
|
@ -1,6 +1,6 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { openUrl } from '../../../utils'
|
||||
import Balance from '../../components/Balance'
|
||||
import { openUrl } from '../../../../utils'
|
||||
import Balance from '../Balance'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import styles from './Accounts.module.css'
|
||||
|
5
src/renderer/src/components/Home/Accounts.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.accounts {
|
||||
composes: balanceWrap from '../../pages/index.module.css';
|
||||
min-height: 55px;
|
||||
padding-top: 2rem;
|
||||
}
|
@ -2,10 +2,10 @@ import React, { useContext } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import posed, { PoseGroup } from 'react-pose'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import { cryptoFormatter } from '../../../utils'
|
||||
import stylesIndex from './index.module.css'
|
||||
import { cryptoFormatter } from '../../../../utils'
|
||||
import stylesIndex from '../../pages/index.module.css'
|
||||
import styles from './Ticker.module.css'
|
||||
import { fadeIn } from '../../components/Animations'
|
||||
import { fadeIn } from '../Animations'
|
||||
|
||||
const Item = posed.div(fadeIn)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import Balance from '../../components/Balance'
|
||||
import { conversions } from '../../../config'
|
||||
import Balance from '../Balance'
|
||||
import { conversions } from '../../../../config'
|
||||
|
||||
const calculateTotalBalance = (accounts, currency) => {
|
||||
const balanceTotalArray = []
|
@ -1,5 +1,5 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { Link } from '@reach/router'
|
||||
import Link from 'next/link'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import IconRocket from '../../images/rocket.svg'
|
||||
import styles from './Welcome.module.css'
|
||||
@ -10,7 +10,7 @@ const Welcome = () => {
|
||||
return (
|
||||
<div className={styles.welcome}>
|
||||
<IconRocket />
|
||||
<Link style={{ color: accentColor }} to="preferences">
|
||||
<Link style={{ color: accentColor }} href="/preferences">
|
||||
Add your first address to get started.
|
||||
</Link>
|
||||
</div>
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { toDataUrl } from 'ethereum-blockies'
|
||||
import posed, { PoseGroup } from 'react-pose'
|
||||
import { fadeIn } from '../../../components/Animations'
|
||||
import { fadeIn } from '../../Animations'
|
||||
import styles from './Saved.module.css'
|
||||
|
||||
export default function Saved({ accounts, handleDelete }) {
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import Store from 'electron-store'
|
||||
import ethereum_address from 'ethereum-address'
|
||||
import Store from 'electron-store'
|
||||
import { AppContext } from '../../../store/createContext'
|
||||
import Saved from './Saved'
|
||||
import New from './New'
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import pkg from '../../../package.json'
|
||||
import pkg from '../../../../package.json'
|
||||
import styles from './Titlebar.module.css'
|
||||
|
||||
const Titlebar = () => (
|
@ -27,7 +27,7 @@ html.fullscreen {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#root {
|
||||
#__next {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
font-size: 1rem;
|
||||
@ -43,7 +43,7 @@ html.fullscreen {
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.dark #root {
|
||||
.dark #__next {
|
||||
color: #e2e2e2;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
32
src/renderer/src/pages/_app.jsx
Normal file
@ -0,0 +1,32 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Router from 'next/router'
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
import '../global.css'
|
||||
import Layout from '../Layout'
|
||||
|
||||
//
|
||||
// Disable zooming
|
||||
//
|
||||
// webFrame.setVisualZoomLevelLimits(1, 1)
|
||||
// webFrame.setLayoutZoomLevelLimits(0, 0)
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on('goTo', (evt, route) => {
|
||||
Router.push(route)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
Component: PropTypes.any.isRequired,
|
||||
pageProps: PropTypes.any.isRequired
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { Link } from '@reach/router'
|
||||
import { AppContext } from '../../store/createContext'
|
||||
import Welcome from './Welcome'
|
||||
import Spinner from '../../components/Spinner'
|
||||
import Divider from '../../components/Divider'
|
||||
import Total from './Total'
|
||||
import Ticker from './Ticker'
|
||||
import Accounts from './Accounts'
|
||||
import IconCog from '../../images/cog.svg'
|
||||
import Link from 'next/link'
|
||||
import { AppContext } from '../store/createContext'
|
||||
import Welcome from '../components/Home/Welcome'
|
||||
import Spinner from '../components/Spinner'
|
||||
import Divider from '../components/Divider'
|
||||
import Total from '../components/Home/Total'
|
||||
import Ticker from '../components/Home/Ticker'
|
||||
import Accounts from '../components/Home/Accounts'
|
||||
import IconCog from '../images/cog.svg'
|
||||
import styles from './index.module.css'
|
||||
|
||||
export default function Home() {
|
||||
@ -16,8 +16,10 @@ export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<main className={styles.main}>
|
||||
<Link className={styles.preferences} to="/preferences">
|
||||
<IconCog />
|
||||
<Link href="/preferences">
|
||||
<a className={styles.preferences}>
|
||||
<IconCog />
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
{needsConfig ? (
|
@ -1,5 +1,5 @@
|
||||
.main {
|
||||
composes: box from '../../components/Box.module.css';
|
||||
composes: box from '../components/Box.module.css';
|
||||
min-height: 222px;
|
||||
display: flex;
|
||||
align-items: center;
|
18
src/renderer/src/pages/preferences.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
import Accounts from '../components/Preferences/Accounts'
|
||||
import styles from './preferences.module.css'
|
||||
|
||||
const Preferences = () => (
|
||||
<div className={styles.preferences}>
|
||||
<h1 className={styles.title}>Preferences</h1>{' '}
|
||||
<Link href="/">
|
||||
<a className={styles.close} title="Close Preferences">
|
||||
×
|
||||
</a>
|
||||
</Link>
|
||||
<Accounts />
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Preferences
|
@ -4,8 +4,12 @@ import ms from 'ms'
|
||||
import { ipcRenderer } from 'electron'
|
||||
import Store from 'electron-store'
|
||||
import { AppContext } from './createContext'
|
||||
import fetchData from '../utils/fetch'
|
||||
import { refreshInterval, conversions, oceanTokenContract } from '../../config'
|
||||
import { fetchData } from '../../../utils'
|
||||
import {
|
||||
refreshInterval,
|
||||
conversions,
|
||||
oceanTokenContract
|
||||
} from '../../../config'
|
||||
|
||||
// construct initial prices Map to get consistent
|
||||
// order for Ticker and Touchbar
|
@ -1,18 +0,0 @@
|
||||
const fetchData = async url => {
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
|
||||
if (response.status !== 200) {
|
||||
return console.log('Non-200 response: ' + response.status) // eslint-disable-line
|
||||
}
|
||||
|
||||
const json = await response.json()
|
||||
if (!json) return
|
||||
|
||||
return json
|
||||
} catch (error) {
|
||||
console.log('Error parsing json:' + error) // eslint-disable-line
|
||||
}
|
||||
}
|
||||
|
||||
export default fetchData
|
20
src/utils.js
@ -1,6 +1,23 @@
|
||||
const { app, shell } = require('electron')
|
||||
const { formatCurrency } = require('@coingecko/cryptoformat')
|
||||
|
||||
const fetchData = async url => {
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
|
||||
if (response.status !== 200) {
|
||||
return console.log('Non-200 response: ' + response.status) // eslint-disable-line
|
||||
}
|
||||
|
||||
const json = await response.json()
|
||||
if (!json) return
|
||||
|
||||
return json
|
||||
} catch (error) {
|
||||
console.log('Error parsing json:' + error) // eslint-disable-line
|
||||
}
|
||||
}
|
||||
|
||||
const isFiat = currency => currency === 'eur' || currency === 'usd'
|
||||
|
||||
const openUrl = url => {
|
||||
@ -65,5 +82,6 @@ module.exports = {
|
||||
rgbaToHex,
|
||||
locale,
|
||||
numberFormatter,
|
||||
cryptoFormatter
|
||||
cryptoFormatter,
|
||||
fetchData
|
||||
}
|
||||
|
@ -1,74 +0,0 @@
|
||||
const path = require('path')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const CopyPlugin = require('copy-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
|
||||
const defaultInclude = [path.resolve(__dirname, 'src', 'renderer')]
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
module.exports = {
|
||||
mode: isDevelopment ? 'development' : 'production',
|
||||
entry: path.resolve(__dirname, 'src', 'renderer', 'index.js'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
filename: 'bundle.js',
|
||||
publicPath: isDevelopment ? '/' : './'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)?$/,
|
||||
use: ['babel-loader'],
|
||||
include: defaultInclude
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
include: defaultInclude
|
||||
},
|
||||
{
|
||||
test: /\.module\.css$/,
|
||||
include: defaultInclude,
|
||||
loader: [
|
||||
isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]___[hash:base64:5]'
|
||||
},
|
||||
localsConvention: 'camelCase',
|
||||
sourceMap: isDevelopment
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif)$/,
|
||||
use: ['file-loader?name=img/[name]__[hash:base64:5].[ext]'],
|
||||
include: defaultInclude
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: ['@svgr/webpack'],
|
||||
include: defaultInclude
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx', '.css']
|
||||
},
|
||||
target: 'electron-renderer',
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin(),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: isDevelopment ? '[name].css' : '[name].[hash].css',
|
||||
chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css'
|
||||
}),
|
||||
new CopyPlugin([
|
||||
{ from: './src/renderer/images/icon.*', to: './', flatten: true }
|
||||
])
|
||||
]
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
const path = require('path')
|
||||
const common = require('./webpack.common.config')
|
||||
const { spawn } = require('child_process')
|
||||
|
||||
module.exports = Object.assign({}, common, {
|
||||
devtool: 'cheap-source-map',
|
||||
devServer: {
|
||||
contentBase: path.resolve(__dirname, 'build'),
|
||||
stats: 'minimal',
|
||||
before: () => {
|
||||
spawn('electron', ['.'], {
|
||||
shell: true,
|
||||
env: process.env,
|
||||
stdio: 'inherit'
|
||||
})
|
||||
.on('close', () => process.exit(0))
|
||||
.on('error', spawnError => console.error(spawnError)) // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
})
|