Initial work on react.

Far from done.
Far from working.
Requires rewrite of UI logic using react patterns.
This commit is contained in:
Daniel Scalzi 2020-03-08 20:40:37 -04:00
parent 9cb10b70af
commit b9536ed014
No known key found for this signature in database
GPG Key ID: D18EA3FB4B142A57
47 changed files with 8827 additions and 568 deletions

View File

@ -1,3 +1,4 @@
// @ts-nocheck
import $ from 'jquery'
import { ipcRenderer, remote, shell, webFrame } from 'electron'
import { LoggerUtil } from '../loggerutil'
@ -107,7 +108,7 @@ function changeAllowPrerelease(val){
function showUpdateUI(info){
//TODO Make this message a bit more informative `${info.version}`
document.getElementById('image_seal_container').setAttribute('update', true)
document.getElementById('image_seal_container').setAttribute('update', 'true')
document.getElementById('image_seal_container').onclick = () => {
/*setOverlayContent('Update Available', 'A new update for the launcher is available. Would you like to install now?', 'Install', 'Later')
setOverlayHandler(() => {
@ -138,6 +139,7 @@ document.addEventListener('readystatechange', function () {
loggerUICore.log('UICore Initializing..')
// Bind close button.
// DONE
Array.from(document.getElementsByClassName('fCb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
@ -146,6 +148,7 @@ document.addEventListener('readystatechange', function () {
})
// Bind restore down button.
// DONE
Array.from(document.getElementsByClassName('fRb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
@ -154,23 +157,24 @@ document.addEventListener('readystatechange', function () {
} else {
window.maximize()
}
document.activeElement.blur()
(document.activeElement as HTMLElement).blur()
})
})
// Bind minimize button.
// DONE
Array.from(document.getElementsByClassName('fMb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
window.minimize()
document.activeElement.blur()
window.minimize();
(document.activeElement as HTMLElement).blur()
})
})
// Remove focus from social media buttons once they're clicked.
Array.from(document.getElementsByClassName('mediaURL')).map(val => {
val.addEventListener('click', e => {
document.activeElement.blur()
(document.activeElement as HTMLElement).blur()
})
})
@ -184,10 +188,10 @@ document.addEventListener('readystatechange', function () {
//const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width
//const targetWidth3 = document.getElementById("launch_button").getBoundingClientRect().width
document.getElementById('launch_details').style.maxWidth = 266.01
document.getElementById('launch_progress').style.width = 170.8
document.getElementById('launch_details_right').style.maxWidth = 170.8
document.getElementById('launch_progress_label').style.width = 53.21
document.getElementById('launch_details').style.maxWidth = '266.01'
document.getElementById('launch_progress').style.width = '170.8'
document.getElementById('launch_details_right').style.maxWidth = '170.8'
document.getElementById('launch_progress_label').style.width = '53.21'
}
@ -209,6 +213,6 @@ $(document).on('click', 'a[href^="http"]', function(event) {
document.addEventListener('keydown', function (e) {
if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){
let window = remote.getCurrentWindow()
window.toggleDevTools()
window.webContents.toggleDevTools()
}
})

8897
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,54 +10,86 @@
"url": "https://github.com/dscalzi/HeliosLauncher/issues"
},
"private": true,
"main": "out/index.js",
"main": "./dist/main.js",
"scripts": {
"clean": "rimraf out",
"clean": "rimraf dist",
"tsc": "tsc",
"build": "npm run clean && npm run tsc",
"start": "electron .",
"cilinux": "node build.js WINDOWS && node build.js LINUX",
"cidarwin": "node build.js MAC",
"dist": "cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true node build.js",
"dist:win": "npm run dist -- WINDOWS",
"dist:mac": "npm run dist -- MAC",
"dist:linux": "npm run dist -- LINUX",
"lint": "eslint --config .eslintrc.json ."
"lint": "eslint --ext=jsx,js,tsx,ts src",
"build-main": "cross-env NODE_ENV=production webpack --config webpack.main.prod.config.js",
"build-renderer": "cross-env NODE_ENV=production webpack --config webpack.renderer.prod.config.js",
"build": "npm run build-main && npm run build-renderer",
"start-renderer-dev": "webpack-dev-server --config webpack.renderer.dev.config.js",
"start-main-dev": "webpack --config webpack.main.config.js && electron ./dist/main.js",
"start-dev": "cross-env START_HOT=1 npm run start-renderer-dev",
"pack": "npm run build && cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true node build.js --dir",
"dist": "npm run build && cross-env ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true node build.js",
"postinstall": "electron-builder install-app-deps"
},
"engines": {
"node": "12.x.x"
},
"dependencies": {
"adm-zip": "^0.4.13",
"async": "^3.1.1",
"adm-zip": "^0.4.14",
"async": "^3.2.0",
"discord-rpc": "3.1.0",
"ejs": "^3.0.1",
"ejs-electron": "^2.0.3",
"electron-updater": "^4.2.0",
"electron-updater": "^4.2.4",
"fs-extra": "^8.1.0",
"github-syntax-dark": "^0.5.0",
"jquery": "^3.4.1",
"request": "^2.88.0",
"semver": "^7.1.1",
"request": "^2.88.2",
"semver": "^7.1.3",
"tar-fs": "^2.0.0",
"winreg": "^1.2.4"
},
"devDependencies": {
"@babel/core": "^7.8.7",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/polyfill": "^7.8.7",
"@babel/preset-env": "^7.8.7",
"@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3",
"@types/adm-zip": "^0.4.32",
"@types/async": "^3.0.5",
"@types/async": "^3.0.8",
"@types/discord-rpc": "^3.0.2",
"@types/fs-extra": "^8.0.1",
"@types/jquery": "^3.3.31",
"@types/node": "^12.12.25",
"@types/fs-extra": "^8.1.0",
"@types/jquery": "^3.3.33",
"@types/node": "^12.12.29",
"@types/react": "^16.9.23",
"@types/react-dom": "^16.9.5",
"@types/react-redux": "^7.1.7",
"@types/request": "^2.48.4",
"@types/tar-fs": "^1.16.2",
"@types/winreg": "^1.2.30",
"cross-env": "^7.0.0",
"electron": "^7.1.10",
"electron-builder": "^22.2.0",
"babel-loader": "^8.0.6",
"cross-env": "^7.0.2",
"css-loader": "^3.4.2",
"electron": "^7.1.14",
"electron-builder": "^22.4.0",
"electron-devtools-installer": "^2.2.4",
"eslint": "^6.8.0",
"fork-ts-checker-webpack-plugin": "^4.0.5",
"helios-distribution-types": "1.0.0-pre.1",
"rimraf": "^3.0.0"
"html-webpack-plugin": "^3.2.0",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"react-hot-loader": "^4.12.19",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"rimraf": "^3.0.2",
"source-map-loader": "^0.2.4",
"style-loader": "^1.1.3",
"typescript": "^3.8.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"webpack-merge": "^4.2.2"
},
"repository": {
"type": "git",

View File

@ -6,7 +6,15 @@ import { format } from "url"
import { autoUpdater } from 'electron-updater'
import isdev from "./isdev"
const ejse = require('ejs-electron')
const installExtensions = async () => {
const installer = require('electron-devtools-installer');
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
return Promise.all(
extensions.map(name => installer.default(installer[name], forceDownload))
).catch(console.log); // eslint-disable-line no-console
};
// Setup auto updater.
function initAutoUpdater(event: any, data: any) {
@ -89,7 +97,11 @@ app.disableHardwareAcceleration()
// be closed automatically when the JavaScript object is garbage collected.
let win: BrowserWindow | null
function createWindow() {
async function createWindow() {
if (process.env.NODE_ENV !== 'production') {
await installExtensions();
}
win = new BrowserWindow({
width: 980,
@ -104,10 +116,10 @@ function createWindow() {
backgroundColor: '#171614'
})
ejse.data('bkid', Math.floor((Math.random() * readdirSync(join(__dirname, '..', 'assets', 'images', 'backgrounds')).length)))
// ejse.data('bkid', Math.floor((Math.random() * readdirSync(join(__dirname, '..', 'assets', 'images', 'backgrounds')).length)))
win.loadURL(format({
pathname: join(__dirname, '..', 'assets', 'templates', 'app.ejs'),
pathname: join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
@ -120,6 +132,13 @@ function createWindow() {
win.resizable = true
if (process.env.NODE_ENV !== 'production') {
// Open DevTools, see https://github.com/electron/electron/issues/12438 for why we wait for dom-ready
win.webContents.once('dom-ready', () => {
win!.webContents.openDevTools();
});
}
win.on('closed', () => {
win = null
})

0
src/renderer/App.css Normal file
View File

21
src/renderer/app.tsx Normal file
View File

@ -0,0 +1,21 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import Application from './components/Application';
// Create main element
const mainElement = document.createElement('div');
document.body.appendChild(mainElement);
// Render components
const render = (Component: () => JSX.Element) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
mainElement
);
};
render(Application);

View File

@ -0,0 +1,14 @@
import { hot } from 'react-hot-loader/root';
import * as React from 'react';
import Frame from './Frame';
const Application = () => (
<>
<Frame />
<div>
Hello World from Electron!
</div>
</>
);
export default hot(Application);

View File

@ -0,0 +1,151 @@
/* Frame Bar */
#frameBar {
position: relative;
z-index: 100;
display: flex;
flex-direction: column;
transition: background-color 1s ease;
/*background-color: rgba(0, 0, 0, 0.5);*/
-webkit-user-select: none;
}
/* Undraggable region on the top of the frame. */
#frameResizableTop {
height: 2px;
width: 100%;
-webkit-app-region: no-drag;
}
/* Flexbox to wrap the main frame content. */
#frameMain {
display: flex;
height: 20px
}
/* Undraggable region on the left and right of the frame. */
.frameResizableVert {
width: 2px;
-webkit-app-region: no-drag;
}
/* Main frame content for windows. */
#frameContentWin {
display: flex;
justify-content: space-between;
width: 100%;
-webkit-app-region: drag;
}
/* Main frame content for darwin. */
#frameContentDarwin {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
-webkit-app-region: drag;
}
/* Frame logo (windows only). */
#frameTitleDock {
padding: 0px 10px;
}
#frameTitleText {
font-size: 14px;
font-family: 'Avenir Medium';
letter-spacing: 0.5px;
}
/* Windows frame button dock. */
#frameButtonDockWin {
-webkit-app-region: no-drag !important;
position: relative;
top: -2px;
right: -2px;
height: 22px;
}
#frameButtonDockWin > .frameButton:not(:first-child) {
margin-left: -4px;
}
/* Darwin frame button dock: NaN; */
#frameButtonDockDarwin {
-webkit-app-region: no-drag !important;
position: relative;
top: -1px;
right: -1px;
}
/* Windows Frame Button Styles. */
.frameButton {
background: none;
border: none;
height: 22px;
width: 39px;
cursor: pointer;
}
.frameButton:hover,
.frameButton:focus {
background: rgba(189, 189, 189, 0.43);
}
.frameButton:active {
background: rgba(156, 156, 156, 0.43);
}
.frameButton:focus {
outline: 0px;
}
/* Close button is red. */
#frameButton_close:hover,
#frameButton_close:focus {
background: rgba(255, 53, 53, 0.61) !important;
}
#frameButton_close:active {
background: rgba(235, 0, 0, 0.61) !important;
}
/* Darwin Frame Button Styles. */
.frameButtonDarwin {
height: 12px;
width: 12px;
border-radius: 50%;
border: 0px;
margin-left: 5px;
-webkit-app-region: no-drag !important;
cursor: pointer;
}
.frameButtonDarwin:focus {
outline: 0px;
}
#frameButtonDarwin_close {
background-color: #e74c32;
}
#frameButtonDarwin_close:hover,
#frameButtonDarwin_close:focus {
background-color: #FF9A8A;
}
#frameButtonDarwin_close:active {
background-color: #ff8d7b;
}
#frameButtonDarwin_minimize {
background-color: #fed045;
}
#frameButtonDarwin_minimize:hover,
#frameButtonDarwin_minimize:focus {
background-color: #FFE9A9;
}
#frameButtonDarwin_minimize:active {
background-color: #ffde7b;
}
#frameButtonDarwin_restoredown {
background-color: #96e734;
}
#frameButtonDarwin_restoredown:hover,
#frameButtonDarwin_restoredown:focus {
background-color: #D6FFA6;
}
#frameButtonDarwin_restoredown:active {
background-color: #bfff76;
}

View File

@ -0,0 +1,64 @@
import * as React from 'react';
import { remote } from 'electron';
import './Frame.css';
require('./Frame.css')
function closeHandler() {
const window = remote.getCurrentWindow();
window.close();
}
function restoreDownHandler() {
const window = remote.getCurrentWindow()
if(window.isMaximized()){
window.unmaximize()
} else {
window.maximize()
}
(document.activeElement as HTMLElement).blur()
}
function minimizeHandler() {
const window = remote.getCurrentWindow()
window.minimize();
(document.activeElement as HTMLElement).blur()
}
const Frame = () => (
<div id="frameBar">
<div id="frameResizableTop" className="frameDragPadder"></div>
<div id="frameMain">
<div className="frameResizableVert frameDragPadder"></div>
{ process.platform === 'darwin' ?
<div id="frameContentDarwin">
<div id="frameButtonDockDarwin">
<button className="frameButtonDarwin" onClick={closeHandler} id="frameButtonDarwin_close" tabIndex={-1}></button>
<button className="frameButtonDarwin" onClick={minimizeHandler} id="frameButtonDarwin_minimize" tabIndex={-1}></button>
<button className="frameButtonDarwin" onClick={restoreDownHandler} id="frameButtonDarwin_restoredown" tabIndex={-1}></button>
</div>
</div>
:
<div id="frameContentWin">
<div id="frameTitleDock">
<span id="frameTitleText">Helios Launcher</span>
</div>
<div id="frameButtonDockWin">
<button className="frameButton" onClick={minimizeHandler} id="frameButton_minimize" tabIndex={-1}>
<svg name="TitleBarMinimize" width="10" height="10" viewBox="0 0 12 12"><rect stroke="#ffffff" fill="#ffffff" width="10" height="1" x="1" y="6"></rect></svg>
</button>
<button className="frameButton" onClick={restoreDownHandler} id="frameButton_restoredown" tabIndex={-1}>
<svg name="TitleBarMaximize" width="10" height="10" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="#ffffff" stroke-width="1.4px"></rect></svg>
</button>
<button className="frameButton" onClick={closeHandler} id="frameButton_close" tabIndex={-1}>
<svg name="TitleBarClose" width="10" height="10" viewBox="0 0 12 12"><polygon stroke="#ffffff" fill="#ffffff" fill-rule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"></polygon></svg>
</button>
</div>
</div>
}
<div className="frameResizableVert frameDragPadder"></div>
</div>
</div>
);
export default Frame;

View File

@ -4,23 +4,25 @@
"target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": [ /* Specify library files to be included in the compilation. */
"ES2019",
"dom"
"DOM",
"ES2019"
],
"allowJs": true, /* Allow javascript files to be compiled. */
"jsx": "react",
// "checkJs": true, /* Report errors in .js files. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": false, /* Generates corresponding '.map' file. */
"outDir": "out", /* Redirect output structure to the directory. */
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
"sourceMap": true, /* Generates corresponding '.map' file. */
"outDir": "dist", /* Redirect output structure to the directory. */
"strict": true,
// "baseUrl": ".", /* Base directory to resolve non-absolute module names. */
// "paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "*": ["node_modules/*"]
// },
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
},
"include": [
"src/**/*"
"./src"
],
"exclude": [ "node_modules" ]
}

21
webpack.base.config.js Normal file
View File

@ -0,0 +1,21 @@
'use strict'
const path = require('path')
module.exports = {
mode: 'development',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
node: {
__dirname: false,
__filename: false
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json']
},
devtool: 'source-map',
plugins: [
]
}

43
webpack.main.config.js Normal file
View File

@ -0,0 +1,43 @@
const webpack = require('webpack')
const merge = require('webpack-merge')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const baseConfig = require('./webpack.base.config')
module.exports = merge.smart(baseConfig, {
target: 'electron-main',
entry: {
main: './src/main/main.ts'
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
'@babel/preset-env',
{ targets: 'maintained node versions' }
],
'@babel/preset-typescript'
],
plugins: [
['@babel/plugin-proposal-class-properties', { loose: true }]
]
}
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin({
reportFiles: ['src/main/**/*']
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
]
})

View File

@ -0,0 +1,7 @@
const merge = require('webpack-merge')
const baseConfig = require('./webpack.main.config')
module.exports = merge.smart(baseConfig, {
mode: 'production'
})

View File

@ -0,0 +1,73 @@
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const baseConfig = require('./webpack.base.config')
module.exports = merge.smart(baseConfig, {
target: 'electron-renderer',
entry: {
app: ['@babel/polyfill','./src/renderer/app.tsx']
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
'@babel/preset-env',
{ targets: { browsers: 'last 2 versions ' } }
],
'@babel/preset-typescript',
'@babel/preset-react'
],
plugins: [
['@babel/plugin-proposal-class-properties', { loose: true }]
]
}
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
},
{
test: /\.(gif|png|jpe?g|svg)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
disable: true
}
}
]
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin({
reportFiles: ['src/renderer/**/*']
}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
]
})

View File

@ -0,0 +1,32 @@
const merge = require('webpack-merge')
const spawn = require('child_process').spawn
const baseConfig = require('./webpack.renderer.config')
module.exports = merge.smart(baseConfig, {
devServer: {
port: 2003,
compress: true,
noInfo: true,
stats: 'errors-only',
inline: true,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
historyApiFallback: {
verbose: true,
disableDotRule: false
},
before() {
if (process.env.START_HOT) {
console.log('Starting main process')
spawn('npm', ['run', 'start-main-dev'], {
shell: true,
env: process.env,
stdio: 'inherit'
})
.on('close', code => process.exit(code))
.on('error', spawnError => console.error(spawnError))
}
}
}
})

View File

@ -0,0 +1,7 @@
const merge = require('webpack-merge')
const baseConfig = require('./webpack.renderer.config')
module.exports = merge.smart(baseConfig, {
mode: 'production'
})