1
0
mirror of https://github.com/pavlobu/deskreen.git synced 2025-05-27 21:00:08 -07:00

start with electron-react-boilerplate

This commit is contained in:
Pavlo Buidenkov 2020-08-08 17:19:38 +03:00
commit a30fa881d0
122 changed files with 40858 additions and 0 deletions

48
.dockerignore Normal file
View File

@ -0,0 +1,48 @@
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# App packaged
release
app/main.prod.js
app/main.prod.js.map
app/renderer.prod.js
app/renderer.prod.js.map
app/style.css
app/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
.*.dockerfile

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

56
.eslintignore Normal file
View File

@ -0,0 +1,56 @@
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# App packaged
release
app/*.main.prod.js
app/main.prod.js
app/main.prod.js.map
app/renderer.prod.js
app/renderer.prod.js.map
app/style.css
app/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
__snapshots__
# Package.json
package.json
.travis.yml
*.css.d.ts
*.sass.d.ts
*.scss.d.ts

26
.eslintrc.js Normal file
View File

@ -0,0 +1,26 @@
module.exports = {
extends: 'erb/typescript',
rules: {
// A temporary hack related to IDE not resolving correct package.json
'import/no-extraneous-dependencies': 'off',
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
project: './tsconfig.json',
tsconfigRootDir: __dirname,
createDefaultProgram: true,
},
settings: {
'import/resolver': {
// See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below
node: {},
webpack: {
config: require.resolve('./configs/webpack.config.eslint.js'),
},
},
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
},
};

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
* text eol=lf
*.png binary
*.jpg binary
*.jpeg binary
*.ico binary
*.icns binary

7
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,7 @@
# TODO: edit funding when ready
# These are supported funding model platforms
github: [deskrin, pavlobu]
patreon: pavlobu
open_collective: todo-add-open-collective-page!

11
.github/ISSUE_TEMPLATE/1-Bug_report.md vendored Normal file
View File

@ -0,0 +1,11 @@
---
name: Bug report
about: You're having technical issues. 🐞
labels: 'bug'
---
<!-- Please use the following issue template or your issue will be closed -->
## TODO
write bug report template

9
.github/ISSUE_TEMPLATE/2-Question.md vendored Normal file
View File

@ -0,0 +1,9 @@
---
name: Question
about: Ask a question.❓
labels: 'question'
---
## TODO
write question template

View File

@ -0,0 +1,5 @@
---
name: Feature request
about: You want something added to the boilerplate. 🎉
labels: 'enhancement'
---

6
.github/config.yml vendored Normal file
View File

@ -0,0 +1,6 @@
requiredHeaders:
- Prerequisites
- Expected Behavior
- Current Behavior
- Possible Solution
- Your Environment

17
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pr
- discussion
- e2e
- enhancement
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

41
.github/workflows/codecov.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: codecov generate
on: [push, pull_request]
jobs:
run:
runs-on: ubuntu-18.04
steps:
- name: Check out Git repository
uses: actions/checkout@v2.3.1
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1.4.2
with:
node-version: 14
- name: yarn install
run: |
yarn install --frozen-lockfile
- name: yarn build
uses: borales/actions-yarn@v2.3.0
with:
cmd: build
- name: yarn test
uses: borales/actions-yarn@v2.3.0
with:
cmd: test
- name: yarn coverage
uses: borales/actions-yarn@v2.3.0
with:
cmd: coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.0.12
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true

65
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,65 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: release all os -- no code signing
jobs:
create-release:
runs-on: ubuntu-18.04
steps:
- name: Checkout code
uses: actions/checkout@v2.3.1
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false
release:
name: Release
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-18.04
artifact_name: 'release/{*.AppImage,*.rpm,*.deb,*.yml}'
- os: windows-2019
artifact_name: 'release/{*.msi,*.exe,*.blockmap,*.yml}'
- os: macos-10.14
artifact_name: 'release/{*.zip,*.dmg,*.blockmap,*.yml}'
steps:
- name: Checkout code
uses: actions/checkout@v2.3.1
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1.4.2
with:
node-version: 14
- name: yarn install --frozen-lockfile
run: |
yarn install --frozen-lockfile
- name: yarn package-ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn package-ci
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: ${{ matrix.artifact_name }}
overwrite: true
file_glob: true

62
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: build and test
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-10.14, windows-2019, ubuntu-18.04]
steps:
- name: Check out Git repository
uses: actions/checkout@v2.3.1
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1.4.2
with:
node-version: 14
- name: yarn install --frozen-lockfile
run: |
yarn install --frozen-lockfile
# following step does code signing when `electron-builder --publish always` (look in package.json)
- name: yarn package-ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn package-ci
- name: yarn build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn build
- name: yarn lint
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn lint
- name: yarn tsc
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn tsc
- name: yarn test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn test
- name: yarn build-e2e
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: yarn build-e2e
- name: yarn test-e2e
uses: GabrielBB/xvfb-action@v1.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
run: yarn test-e2e

55
.gitignore vendored Normal file
View File

@ -0,0 +1,55 @@
.nyc_output
.scannerwork/
test-reports/
test-reporter.xml
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
.eslintcache
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# OSX
.DS_Store
# App packaged
release
app/main.prod.js
app/main.prod.js.map
app/renderer.prod.js
app/renderer.prod.js.map
app/style.css
app/style.css.map
dist
dll
main.js
main.js.map
.idea
npm-debug.log.*
*.css.d.ts
*.sass.d.ts
*.scss.d.ts

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"msjsdiag.debugger-for-chrome"
]
}

28
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,28 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Electron: Main",
"protocol": "inspector",
"runtimeExecutable": "yarn",
"runtimeArgs": ["start-main-debug"],
"preLaunchTask": "Start Webpack Dev"
},
{
"name": "Deskrin: Renderer",
"type": "chrome",
"request": "attach",
"port": 9223,
"webRoot": "${workspaceFolder}",
"timeout": 15000
}
],
"compounds": [
{
"name": "Deskrin: All",
"configurations": ["Deskrin: Main", "Deskrin: Renderer"]
}
]
}

30
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"files.associations": {
".babelrc": "jsonc",
".eslintrc": "jsonc",
".prettierrc": "jsonc",
".stylelintrc": "json",
".dockerignore": "ignore",
".eslintignore": "ignore"
},
"javascript.validate.enable": false,
"javascript.format.enable": false,
"typescript.format.enable": false,
"search.exclude": {
".git": true,
".eslintcache": true,
"app/dist": true,
"app/main.prod.js": true,
"app/main.prod.js.map": true,
"bower_components": true,
"dll": true,
"release": true,
"node_modules": true,
"npm-debug.log.*": true,
"test/**/__snapshots__": true,
"yarn.lock": true,
"*.{css,sass,scss}.d.ts": true
}
}

25
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"label": "Start Webpack Dev",
"script": "start-renderer-dev",
"options": {
"cwd": "${workspaceFolder}"
},
"isBackground": true,
"problemMatcher": {
"owner": "custom",
"pattern": {
"regexp": "____________"
},
"background": {
"activeOnStart": true,
"beginsPattern": "Compiling\\.\\.\\.$",
"endsPattern": "(Compiled successfully|Failed to compile)\\.$"
}
}
}
]
}

3
CHANGELOG.md Normal file
View File

@ -0,0 +1,3 @@
# 0.0.1 (8 Aug 2020)
Started with [electron-react-boilerplate v1.3.0](https://github.com/electron-react-boilerplate/electron-react-boilerplate)

76
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at pavlobu@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2020-present Deskrin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

45
README.md Normal file
View File

@ -0,0 +1,45 @@
[![codecov](https://codecov.io/gh/pavlobu/test-electron-boilerplate-ci/branch/master/graph/badge.svg)](https://codecov.io/gh/pavlobu/test-electron-boilerplate-ci)
![build and test](https://github.com/pavlobu/test-electron-boilerplate-ci/workflows/build%20and%20test/badge.svg)
![release all os -- no code signing](https://github.com/pavlobu/test-electron-boilerplate-ci/workflows/release%20all%20os%20--%20no%20code%20signing/badge.svg)
![codecov generate](https://github.com/pavlobu/test-electron-boilerplate-ci/workflows/codecov%20generate/badge.svg)
## Howto:
### to generate test coverage results
```
yarn coverage
```
### to run sonarqube scanner to put results to sonarqube
```
sonar-scanner
```
### sonar-project.properties example:
```
sonar.projectKey=test-electron-react-boilerplate
# sonar.testExecutionReportPaths=test-reporter.xml
sonar.testExecutionReportPaths=test-reports/test-reporter.xml
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.sources=./app
sonar.tests=./test
sonar.host.url=http://localhost:9000
sonar.login=d0c254aaff5ebd89dd5c6f0663238ab6ad5fddea
# sonar.login=039884f95817f7b26d781d7cdd47430cb3734a0a
```
## Maintainer
- [Pavlo (Paul) Buidenkov](https://github.com/pavlo/buidenkov)
## License
MIT © [Deskrin](https://github.com/pavlobu/deskrin)
## Copyright
MIT © [Electron React Boilerplate](https://github.com/electron-react-boilerplate)

View File

@ -0,0 +1,4 @@
{
"mainWindowUrl": "./app.html",
"appPath": "."
}

28
app/Routes.tsx Normal file
View File

@ -0,0 +1,28 @@
/* eslint react/jsx-props-no-spreading: off */
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import routes from './constants/routes.json';
import App from './containers/App';
import HomePage from './containers/HomePage';
// Lazily load routes and code split with webpacck
const LazyCounterPage = React.lazy(() =>
import(/* webpackChunkName: "CounterPage" */ './containers/CounterPage')
);
const CounterPage = (props: Record<string, any>) => (
<React.Suspense fallback={<h1>Loading...</h1>}>
<LazyCounterPage {...props} />
</React.Suspense>
);
export default function Routes() {
return (
<App>
<Switch>
<Route path={routes.COUNTER} component={CounterPage} />
<Route path={routes.HOME} component={HomePage} />
</Switch>
</App>
);
}

47
app/app.global.css Normal file
View File

@ -0,0 +1,47 @@
/*
* @NOTE: Prepend a `~` to css file paths that are in your node_modules
* See https://github.com/webpack-contrib/sass-loader#imports
*/
@import '~@fortawesome/fontawesome-free/css/all.css';
body {
position: relative;
color: white;
height: 100vh;
background-color: #232c39;
background-image: linear-gradient(
45deg,
rgba(0, 216, 255, 0.5) 10%,
rgba(0, 1, 127, 0.7)
);
font-family: Arial, Helvetica, Helvetica Neue, serif;
overflow-y: hidden;
}
h2 {
margin: 0;
font-size: 2.25rem;
font-weight: bold;
letter-spacing: -0.025em;
color: #fff;
}
p {
font-size: 24px;
}
li {
list-style: none;
}
a {
color: white;
opacity: 0.75;
text-decoration: none;
}
a:hover {
opacity: 1;
text-decoration: none;
cursor: pointer;
}

50
app/app.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Hello Deskrin!</title>
<script>
(() => {
if (
typeof process !== 'object' ||
(typeof process === 'object' && !process.env.START_HOT)
) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './dist/style.css';
// HACK: Writing the script path should be done with webpack
document.getElementsByTagName('head')[0].appendChild(link);
}
})();
</script>
</head>
<body>
<div id="root"></div>
<script>
if (typeof process === 'object') {
const scripts = [];
if (process.env.NODE_ENV === 'development') {
// Dynamically insert the DLL script in development env in the
// renderer process
scripts.push('../dll/renderer.dev.dll.js');
}
if (process.env.START_HOT) {
// Dynamically insert the bundled app script in the renderer process
const port = process.env.PORT || 1212;
scripts.push(`http://localhost:${port}/dist/renderer.dev.js`);
} else {
scripts.push('./dist/renderer.prod.js');
}
if (scripts.length) {
document.write(
scripts
.map((script) => `<script defer src="${script}"><\/script>`)
.join('')
);
}
}
</script>
</body>
</html>

BIN
app/app.icns Normal file

Binary file not shown.

14
app/components/Home.css Normal file
View File

@ -0,0 +1,14 @@
.container {
position: absolute;
top: 30%;
left: 10px;
text-align: center;
}
.container h2 {
font-size: 5rem;
}
.container a {
font-size: 1.4rem;
}

13
app/components/Home.tsx Normal file
View File

@ -0,0 +1,13 @@
import React from 'react';
import { Link } from 'react-router-dom';
import routes from '../constants/routes.json';
import styles from './Home.css';
export default function Home(): JSX.Element {
return (
<div className={styles.container} data-tid="container">
<h2>Home</h2>
<Link to={routes.COUNTER}>to Counter</Link>
</div>
);
}

9
app/components/css.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
declare module '*.scss' {
const content: { [className: string]: string };
export default content;
}
declare module '*.css' {
const content: { [className: string]: string };
export default content;
}

View File

@ -0,0 +1,4 @@
{
"HOME": "/",
"COUNTER": "/counter"
}

10
app/containers/App.tsx Normal file
View File

@ -0,0 +1,10 @@
import React, { ReactNode } from 'react';
type Props = {
children: ReactNode;
};
export default function App(props: Props) {
const { children } = props;
return <>{children}</>;
}

View File

@ -0,0 +1,6 @@
import React from 'react';
import Counter from '../features/counter/Counter';
export default function CounterPage() {
return <Counter />;
}

View File

@ -0,0 +1,6 @@
import React from 'react';
import Home from '../components/Home';
export default function HomePage() {
return <Home />;
}

22
app/containers/Root.tsx Normal file
View File

@ -0,0 +1,22 @@
import React from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import { hot } from 'react-hot-loader/root';
import { History } from 'history';
import { Store } from '../store';
import Routes from '../Routes';
type Props = {
store: Store;
history: History;
};
const Root = ({ store, history }: Props) => (
<Provider store={store}>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</Provider>
);
export default hot(Root);

View File

@ -0,0 +1,37 @@
.backButton {
position: absolute;
}
.counter {
position: absolute;
top: 30%;
left: 45%;
font-size: 10rem;
font-weight: bold;
letter-spacing: -0.025em;
}
.btnGroup {
position: relative;
top: 500px;
width: 480px;
margin: 0 auto;
}
.btn {
font-size: 1.6rem;
font-weight: bold;
background-color: #fff;
border-radius: 50%;
margin: 10px;
width: 100px;
height: 100px;
opacity: 0.7;
cursor: pointer;
font-family: Arial, Helvetica, Helvetica Neue, sans-serif;
}
.btn:hover {
color: white;
background-color: rgba(0, 0, 0, 0.5);
}

View File

@ -0,0 +1,71 @@
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import styles from './Counter.css';
import routes from '../../constants/routes.json';
import {
increment,
decrement,
incrementIfOdd,
incrementAsync,
selectCount,
} from './counterSlice';
export default function Counter() {
const dispatch = useDispatch();
const value = useSelector(selectCount);
return (
<div>
<div className={styles.backButton} data-tid="backButton">
<Link to={routes.HOME}>
<i className="fa fa-arrow-left fa-3x" />
</Link>
</div>
<div className={`counter ${styles.counter}`} data-tid="counter">
{value}
</div>
<div className={styles.btnGroup}>
<button
className={styles.btn}
onClick={() => {
dispatch(increment());
}}
data-tclass="btn"
type="button"
>
<i className="fa fa-plus" />
</button>
<button
className={styles.btn}
onClick={() => {
dispatch(decrement());
}}
data-tclass="btn"
type="button"
>
<i className="fa fa-minus" />
</button>
<button
className={styles.btn}
onClick={() => {
dispatch(incrementIfOdd());
}}
data-tclass="btn"
type="button"
>
odd
</button>
<button
className={styles.btn}
onClick={() => {
dispatch(incrementAsync());
}}
data-tclass="btn"
type="button"
>
async
</button>
</div>
</div>
);
}

View File

@ -0,0 +1,38 @@
import { createSlice } from '@reduxjs/toolkit';
// eslint-disable-next-line import/no-cycle
import { AppThunk, RootState } from '../../store';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export const incrementIfOdd = (): AppThunk => {
return (dispatch, getState) => {
const state = getState();
if (state.counter.value % 2 === 0) {
return;
}
dispatch(increment());
};
};
export const incrementAsync = (delay = 1000): AppThunk => (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, delay);
};
export default counterSlice.reducer;
export const selectCount = (state: RootState) => state.counter.value;

20
app/index.tsx Normal file
View File

@ -0,0 +1,20 @@
import React, { Fragment } from 'react';
import { render } from 'react-dom';
import { AppContainer as ReactHotAppContainer } from 'react-hot-loader';
import { history, configuredStore } from './store';
import './app.global.css';
const store = configuredStore();
const AppContainer = process.env.PLAIN_HMR ? Fragment : ReactHotAppContainer;
document.addEventListener('DOMContentLoaded', () => {
// eslint-disable-next-line global-require
const Root = require('./containers/Root').default;
render(
<AppContainer>
<Root store={store} history={history} />
</AppContainer>,
document.getElementById('root')
);
});

129
app/main.dev.ts Normal file
View File

@ -0,0 +1,129 @@
/* eslint global-require: off, no-console: off */
/**
* This module executes inside of electron's main process. You can start
* electron renderer process from here and communicate with the other processes
* through IPC.
*
* When running `yarn build` or `yarn build-main`, this file is compiled to
* `./app/main.prod.js` using webpack. This gives us some performance wins.
*/
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import path from 'path';
import { app, BrowserWindow } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import signalingServer from './server/signalingServer';
import MenuBuilder from './menu';
signalingServer.start();
export default class AppUpdater {
constructor() {
log.transports.file.level = 'info';
autoUpdater.logger = log;
autoUpdater.checkForUpdatesAndNotify();
}
}
let mainWindow: BrowserWindow | null = null;
if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
}
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
require('electron-debug')();
}
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);
};
const createWindow = async () => {
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
await installExtensions();
}
mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728,
webPreferences:
(process.env.NODE_ENV === 'development' ||
process.env.E2E_BUILD === 'true') &&
process.env.ERB_SECURE !== 'true'
? {
nodeIntegration: true,
}
: {
preload: path.join(__dirname, 'dist/renderer.prod.js'),
},
});
mainWindow.loadURL(`file://${__dirname}/app.html`);
// @TODO: Use 'ready-to-show' event
// https://github.com/electron/electron/blob/master/docs/api/browser-window.md#using-ready-to-show-event
mainWindow.webContents.on('did-finish-load', () => {
if (!mainWindow) {
throw new Error('"mainWindow" is not defined');
}
if (process.env.START_MINIMIZED) {
mainWindow.minimize();
} else {
mainWindow.show();
mainWindow.focus();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
const menuBuilder = new MenuBuilder(mainWindow);
menuBuilder.buildMenu();
// Remove this if your app does not use auto updates
// eslint-disable-next-line
new AppUpdater();
};
/**
* Add event listeners...
*/
app.on('window-all-closed', () => {
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
if (process.platform !== 'darwin') {
app.quit();
}
});
if (process.env.E2E_BUILD === 'true') {
// eslint-disable-next-line promise/catch-or-return
app.whenReady().then(createWindow);
} else {
app.on('ready', createWindow);
}
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) createWindow();
});

1
app/main.prod.js.LICENSE Normal file
View File

@ -0,0 +1 @@
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */

View File

@ -0,0 +1,266 @@
/*!
* accepts
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* body-parser
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* body-parser
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* bytes
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015 Jed Watson
* MIT Licensed
*/
/*!
* content-disposition
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* content-type
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* depd
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* destroy
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* ee-first
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* encodeurl
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* escape-html
* Copyright(c) 2012-2013 TJ Holowaychuk
* Copyright(c) 2015 Andreas Lubbe
* Copyright(c) 2015 Tiancheng "Timothy" Gu
* MIT Licensed
*/
/*!
* etag
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* finalhandler
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* forwarded
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* fresh
* Copyright(c) 2012 TJ Holowaychuk
* Copyright(c) 2016-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* http-errors
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* media-typer
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* merge-descriptors
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* methods
* Copyright(c) 2013-2014 TJ Holowaychuk
* Copyright(c) 2015-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* mime-db
* Copyright(c) 2014 Jonathan Ong
* MIT Licensed
*/
/*!
* mime-types
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* negotiator
* Copyright(c) 2012 Federico Romero
* Copyright(c) 2012-2014 Isaac Z. Schlueter
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* on-finished
* Copyright(c) 2013 Jonathan Ong
* Copyright(c) 2014 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* parseurl
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* proxy-addr
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* range-parser
* Copyright(c) 2012-2014 TJ Holowaychuk
* Copyright(c) 2015-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* raw-body
* Copyright(c) 2013-2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* send
* Copyright(c) 2012 TJ Holowaychuk
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* serve-static
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2014-2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* statuses
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* toidentifier
* Copyright(c) 2016 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* type-is
* Copyright(c) 2014 Jonathan Ong
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* unpipe
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/
/*!
* vary
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */

293
app/menu.ts Normal file
View File

@ -0,0 +1,293 @@
import {
app,
Menu,
shell,
BrowserWindow,
MenuItemConstructorOptions,
} from 'electron';
import signalingServer from './server/signalingServer';
interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions {
selector?: string;
submenu?: DarwinMenuItemConstructorOptions[] | Menu;
}
export default class MenuBuilder {
mainWindow: BrowserWindow;
constructor(mainWindow: BrowserWindow) {
this.mainWindow = mainWindow;
}
buildMenu(): Menu {
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
this.setupDevelopmentEnvironment();
}
const template =
process.platform === 'darwin'
? this.buildDarwinTemplate()
: this.buildDefaultTemplate();
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
return menu;
}
setupDevelopmentEnvironment(): void {
this.mainWindow.webContents.on('context-menu', (_, props) => {
const { x, y } = props;
Menu.buildFromTemplate([
{
label: 'Inspect element',
click: () => {
this.mainWindow.webContents.inspectElement(x, y);
},
},
]).popup({ window: this.mainWindow });
});
}
buildDarwinTemplate(): MenuItemConstructorOptions[] {
const subMenuAbout: DarwinMenuItemConstructorOptions = {
label: 'Deskrin',
submenu: [
{
label: 'About Deskrin',
selector: 'orderFrontStandardAboutPanel:',
},
{ type: 'separator' },
{ label: 'Services', submenu: [] },
{ type: 'separator' },
{
label: 'Hide Deskrin',
accelerator: 'Command+H',
selector: 'hide:',
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
selector: 'hideOtherApplications:',
},
{ label: 'Show All', selector: 'unhideAllApplications:' },
{ type: 'separator' },
{
label: 'Quit',
accelerator: 'Command+Q',
click: () => {
signalingServer.stop();
app.quit();
},
},
],
};
const subMenuEdit: DarwinMenuItemConstructorOptions = {
label: 'Edit',
submenu: [
{ label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' },
{ label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' },
{ type: 'separator' },
{ label: 'Cut', accelerator: 'Command+X', selector: 'cut:' },
{ label: 'Copy', accelerator: 'Command+C', selector: 'copy:' },
{ label: 'Paste', accelerator: 'Command+V', selector: 'paste:' },
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:',
},
],
};
const subMenuViewDev: MenuItemConstructorOptions = {
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: () => {
this.mainWindow.webContents.reload();
},
},
{
label: 'Toggle Full Screen',
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
},
{
label: 'Toggle Developer Tools',
accelerator: 'Alt+Command+I',
click: () => {
this.mainWindow.webContents.toggleDevTools();
},
},
],
};
const subMenuViewProd: MenuItemConstructorOptions = {
label: 'View',
submenu: [
{
label: 'Toggle Full Screen',
accelerator: 'Ctrl+Command+F',
click: () => {
this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen());
},
},
],
};
const subMenuWindow: DarwinMenuItemConstructorOptions = {
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:',
},
{ label: 'Close', accelerator: 'Command+W', selector: 'performClose:' },
{ type: 'separator' },
{ label: 'Bring All to Front', selector: 'arrangeInFront:' },
],
};
const subMenuHelp: MenuItemConstructorOptions = {
label: 'Help',
submenu: [
{
label: 'Learn More',
click() {
shell.openExternal('https://electronjs.org');
},
},
{
label: 'Documentation',
click() {
shell.openExternal(
'https://github.com/electron/electron/tree/master/docs#readme'
);
},
},
{
label: 'Community Discussions',
click() {
shell.openExternal('https://www.electronjs.org/community');
},
},
{
label: 'Search Issues',
click() {
shell.openExternal('https://github.com/electron/electron/issues');
},
},
],
};
const subMenuView =
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
? subMenuViewDev
: subMenuViewProd;
return [subMenuAbout, subMenuEdit, subMenuView, subMenuWindow, subMenuHelp];
}
buildDefaultTemplate() {
const templateDefault = [
{
label: '&File',
submenu: [
{
label: '&Open',
accelerator: 'Ctrl+O',
},
{
label: '&Close',
accelerator: 'Ctrl+W',
click: () => {
this.mainWindow.close();
},
},
],
},
{
label: '&View',
submenu:
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
? [
{
label: '&Reload',
accelerator: 'Ctrl+R',
click: () => {
this.mainWindow.webContents.reload();
},
},
{
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
},
},
{
label: 'Toggle &Developer Tools',
accelerator: 'Alt+Ctrl+I',
click: () => {
this.mainWindow.webContents.toggleDevTools();
},
},
]
: [
{
label: 'Toggle &Full Screen',
accelerator: 'F11',
click: () => {
this.mainWindow.setFullScreen(
!this.mainWindow.isFullScreen()
);
},
},
],
},
{
label: 'Help',
submenu: [
{
label: 'Learn More',
click() {
shell.openExternal('https://electronjs.org');
},
},
{
label: 'Documentation',
click() {
shell.openExternal(
'https://github.com/electron/electron/tree/master/docs#readme'
);
},
},
{
label: 'Community Discussions',
click() {
shell.openExternal('https://www.electronjs.org/community');
},
},
{
label: 'Search Issues',
click() {
shell.openExternal('https://github.com/electron/electron/issues');
},
},
],
},
];
return templateDefault;
}
}

5
app/package-lock.json generated Normal file
View File

@ -0,0 +1,5 @@
{
"name": "deskrin",
"version": "0.0.1",
"lockfileVersion": 1
}

18
app/package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "deskrin",
"productName": "deskrin",
"version": "0.0.1",
"description": "TODO: write description about this project",
"main": "./main.prod.js",
"author": {
"name": "Pavlo (Paul) Buidenkov",
"email": "pavlobu@gmail.com",
"url": "https://github.com/pavlobu"
},
"scripts": {
"electron-rebuild": "node -r ../internals/scripts/BabelRegister.js ../internals/scripts/ElectronRebuild.js",
"postinstall": "yarn electron-rebuild"
},
"license": "MIT",
"dependencies": {}
}

12
app/rootReducer.ts Normal file
View File

@ -0,0 +1,12 @@
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';
import { History } from 'history';
// eslint-disable-next-line import/no-cycle
import counterReducer from './features/counter/counterSlice';
export default function createRootReducer(history: History) {
return combineReducers({
router: connectRouter(history),
counter: counterReducer,
});
}

View File

@ -0,0 +1,70 @@
import { Server } from 'http';
// import express, { Request, Response, NextFunction } from 'express';
import express from 'express';
import getRandomPort from '../utils/server/getRandomPort';
// import * as bodyParser from "body-parser";
// import express from "express";
// import { Routes } from "./routes";
class SignalingServer {
private static instance: SignalingServer;
public expressApp: express.Application;
public count: number;
public server: Server;
public port: number;
// public routePrv: Routes = new Routes();
constructor() {
this.expressApp = express();
this.count = 0;
this.config();
this.server = new Server();
this.port = 3131;
// this.routePrv.routes(this.app);
}
public async start(): Promise<Server> {
this.port = await getRandomPort();
this.server = this.expressApp.listen(this.port);
console.log(`\n\nSignaling server started at port: ${this.port}`);
return this.server;
}
public stop(): void {
this.server.close();
}
private config(): void {
// support application/json type post data
// this.app.use(bodyParser.json());
// support application/x-www-form-urlencoded post data
// this.app.use(bodyParser.urlencoded({ extended: false }));
// responde with indented JSON string
// this.app.set("json spaces", 2);
this.expressApp.get('/', (_, res) => {
console.log(this.count);
this.count += 1;
res.status(200);
res.write('Hello World');
res.send();
});
this.expressApp.get('/favicon.ico', (_, res) => {
res.status(204);
res.send();
});
}
public static getInstance(): SignalingServer {
if (!SignalingServer.instance) {
SignalingServer.instance = new SignalingServer();
}
return SignalingServer.instance;
}
}
export default SignalingServer.getInstance();

47
app/store.ts Normal file
View File

@ -0,0 +1,47 @@
import { configureStore, getDefaultMiddleware, Action } from '@reduxjs/toolkit';
import { createHashHistory } from 'history';
import { routerMiddleware } from 'connected-react-router';
import { createLogger } from 'redux-logger';
import { ThunkAction } from 'redux-thunk';
// eslint-disable-next-line import/no-cycle
import createRootReducer from './rootReducer';
export const history = createHashHistory();
const rootReducer = createRootReducer(history);
export type RootState = ReturnType<typeof rootReducer>;
const router = routerMiddleware(history);
const middleware = [...getDefaultMiddleware(), router];
const excludeLoggerEnvs = ['test', 'production'];
const shouldIncludeLogger = !excludeLoggerEnvs.includes(
process.env.NODE_ENV || ''
);
if (shouldIncludeLogger) {
const logger = createLogger({
level: 'info',
collapsed: true,
});
middleware.push(logger);
}
export const configuredStore = (initialState?: RootState) => {
// Create Store
const store = configureStore({
reducer: rootReducer,
middleware,
preloadedState: initialState,
});
if (process.env.NODE_ENV === 'development' && module.hot) {
module.hot.accept(
'./rootReducer',
// eslint-disable-next-line global-require
() => store.replaceReducer(require('./rootReducer').default)
);
}
return store;
};
export type Store = ReturnType<typeof configuredStore>;
export type AppThunk = ThunkAction<void, RootState, unknown, Action<string>>;

View File

@ -0,0 +1,15 @@
import getPort from 'get-port';
export function shuffle(array: number[]) {
array.sort(() => Math.random() - 0.5);
}
export default async (): Promise<number> => {
let res = 3131;
const range = Array.from(getPort.makeRange(2000, 9999));
shuffle(range);
res = await getPort({
port: range,
});
return res;
};

4
app/yarn.lock Normal file
View File

@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

62
babel.config.js Normal file
View File

@ -0,0 +1,62 @@
/* eslint global-require: off, import/no-extraneous-dependencies: off */
const developmentEnvironments = ['development', 'test'];
const developmentPlugins = [require('react-hot-loader/babel')];
const productionPlugins = [
require('babel-plugin-dev-expression'),
// babel-preset-react-optimize
require('@babel/plugin-transform-react-constant-elements'),
require('@babel/plugin-transform-react-inline-elements'),
require('babel-plugin-transform-react-remove-prop-types'),
];
module.exports = (api) => {
// See docs about api at https://babeljs.io/docs/en/config-files#apicache
const development = api.env(developmentEnvironments);
return {
presets: [
// @babel/preset-env will automatically target our browserslist targets
require('@babel/preset-env'),
require('@babel/preset-typescript'),
[require('@babel/preset-react'), { development }],
],
plugins: [
// Stage 0
require('@babel/plugin-proposal-function-bind'),
// Stage 1
require('@babel/plugin-proposal-export-default-from'),
require('@babel/plugin-proposal-logical-assignment-operators'),
[require('@babel/plugin-proposal-optional-chaining'), { loose: false }],
[
require('@babel/plugin-proposal-pipeline-operator'),
{ proposal: 'minimal' },
],
[
require('@babel/plugin-proposal-nullish-coalescing-operator'),
{ loose: false },
],
require('@babel/plugin-proposal-do-expressions'),
// Stage 2
[require('@babel/plugin-proposal-decorators'), { legacy: true }],
require('@babel/plugin-proposal-function-sent'),
require('@babel/plugin-proposal-export-namespace-from'),
require('@babel/plugin-proposal-numeric-separator'),
require('@babel/plugin-proposal-throw-expressions'),
// Stage 3
require('@babel/plugin-syntax-dynamic-import'),
require('@babel/plugin-syntax-import-meta'),
[require('@babel/plugin-proposal-class-properties'), { loose: true }],
require('@babel/plugin-proposal-json-strings'),
...(development ? developmentPlugins : productionPlugins),
],
};
};

7
configs/.eslintrc Normal file
View File

@ -0,0 +1,7 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off"
}
}

View File

@ -0,0 +1,48 @@
/**
* Base webpack config used across other specific configs
*/
import path from 'path';
import webpack from 'webpack';
import { dependencies as externals } from '../app/package.json';
export default {
externals: [...Object.keys(externals || {})],
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
],
},
output: {
path: path.join(__dirname, '..', 'app'),
// https://github.com/webpack/webpack/issues/1114
libraryTarget: 'commonjs2',
},
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
modules: [path.join(__dirname, '..', 'app'), 'node_modules'],
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
}),
new webpack.NamedModulesPlugin(),
],
};

View File

@ -0,0 +1,4 @@
/* eslint import/no-unresolved: off, import/no-self-import: off */
require('@babel/register');
module.exports = require('./webpack.config.renderer.dev.babel').default;

View File

@ -0,0 +1,76 @@
/**
* Webpack config for production electron main process
*/
import path from 'path';
import webpack from 'webpack';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
import DeleteSourceMaps from '../internals/scripts/DeleteSourceMaps';
CheckNodeEnv('production');
DeleteSourceMaps();
export default merge(baseConfig, {
devtool: process.env.DEBUG_PROD === 'true' ? 'source-map' : 'none',
mode: 'production',
target: 'electron-main',
entry: './app/main.dev.ts',
output: {
path: path.join(__dirname, '..'),
filename: './app/main.prod.js',
},
optimization: {
minimizer: process.env.E2E_BUILD
? []
: [
new TerserPlugin({
parallel: true,
sourceMap: true,
cache: true,
}),
],
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: false,
START_MINIMIZED: false,
E2E_BUILD: false,
}),
],
/**
* Disables webpack processing of __dirname and __filename.
* If you run the bundle in node.js it falls back to these values of node.js.
* https://github.com/webpack/webpack/issues/2010
*/
node: {
__dirname: false,
__filename: false,
},
});

View File

@ -0,0 +1,273 @@
/**
* Build config for development electron renderer process that uses
* Hot-Module-Replacement
*
* https://webpack.js.org/concepts/hot-module-replacement/
*/
import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import chalk from 'chalk';
import { merge } from 'webpack-merge';
import { spawn, execSync } from 'child_process';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
// at the dev webpack config is not accidentally run in a production environment
if (process.env.NODE_ENV === 'production') {
CheckNodeEnv('development');
}
const port = process.env.PORT || 1212;
const publicPath = `http://localhost:${port}/dist`;
const dll = path.join(__dirname, '..', 'dll');
const manifest = path.resolve(dll, 'renderer.json');
const requiredByDLLConfig = module.parent.filename.includes(
'webpack.config.renderer.dev.dll'
);
/**
* Warn if the DLL is not built
*/
if (!requiredByDLLConfig && !(fs.existsSync(dll) && fs.existsSync(manifest))) {
console.log(
chalk.black.bgYellow.bold(
'The DLL files are missing. Sit back while we build them for you with "yarn build-dll"'
)
);
execSync('yarn build-dll');
}
export default merge(baseConfig, {
devtool: 'inline-source-map',
mode: 'development',
target: 'electron-renderer',
entry: [
'core-js',
'regenerator-runtime/runtime',
...(process.env.PLAIN_HMR ? [] : ['react-hot-loader/patch']),
`webpack-dev-server/client?http://localhost:${port}/`,
'webpack/hot/only-dev-server',
require.resolve('../app/index.tsx'),
],
output: {
publicPath: `http://localhost:${port}/dist/`,
filename: 'renderer.dev.js',
},
module: {
rules: [
{
test: /\.global\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /^((?!\.global).)*\.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
sourceMap: true,
importLoaders: 1,
},
},
],
},
// SASS support - compile all .global.scss files and pipe it to style.css
{
test: /\.global\.(scss|sass)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'sass-loader',
},
],
},
// SASS support - compile all other .scss files and pipe it to style.css
{
test: /^((?!\.global).)*\.(scss|sass)$/,
use: [
{
loader: 'typings-for-css-modules-loader',
},
{
loader: 'typings-for-css-modules-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
sourceMap: true,
importLoaders: 1,
},
},
{
loader: 'sass-loader',
},
],
},
// WOFF Font
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// WOFF2 Font
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// TTF Font
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
},
// EOT Font
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
// SVG Font
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml',
},
},
},
// Common Image Formats
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
use: 'url-loader',
},
],
},
resolve: {
alias: {
'react-dom': '@hot-loader/react-dom',
},
},
plugins: [
requiredByDLLConfig
? null
: new webpack.DllReferencePlugin({
context: path.join(__dirname, '..', 'dll'),
manifest: require(manifest),
sourceType: 'var',
}),
new webpack.HotModuleReplacementPlugin({
multiStep: true,
}),
new webpack.NoEmitOnErrorsPlugin(),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*
* By default, use 'development' as NODE_ENV. This can be overriden with
* 'staging', for example, by changing the ENV variables in the npm scripts
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
}),
],
node: {
__dirname: false,
__filename: false,
},
devServer: {
port,
publicPath,
compress: true,
noInfo: false,
stats: 'errors-only',
inline: true,
lazy: false,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' },
contentBase: path.join(__dirname, 'dist'),
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/,
poll: 100,
},
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,72 @@
/**
* Builds the DLL for development electron renderer process
*/
import webpack from 'webpack';
import path from 'path';
import { merge } from 'webpack-merge';
import baseConfig from './webpack.config.base';
import { dependencies } from '../package.json';
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
CheckNodeEnv('development');
const dist = path.join(__dirname, '..', 'dll');
export default merge(baseConfig, {
context: path.join(__dirname, '..'),
devtool: 'eval',
mode: 'development',
target: 'electron-renderer',
externals: ['fsevents', 'crypto-browserify'],
/**
* Use `module` from `webpack.config.renderer.dev.js`
*/
module: require('./webpack.config.renderer.dev.babel').default.module,
entry: {
renderer: Object.keys(dependencies || {}),
},
output: {
library: 'renderer',
path: dist,
filename: '[name].dev.dll.js',
libraryTarget: 'var',
},
plugins: [
new webpack.DllPlugin({
path: path.join(dist, '[name].json'),
name: '[name]',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: path.join(__dirname, '..', 'app'),
output: {
path: path.join(__dirname, '..', 'dll'),
},
},
}),
],
});

View File

@ -0,0 +1,226 @@
/**
* Build config for electron renderer process
*/
import path from 'path';
import webpack from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../internals/scripts/CheckNodeEnv';
import DeleteSourceMaps from '../internals/scripts/DeleteSourceMaps';
CheckNodeEnv('production');
DeleteSourceMaps();
export default merge(baseConfig, {
devtool: process.env.DEBUG_PROD === 'true' ? 'source-map' : 'none',
mode: 'production',
target: process.env.E2E_BUILD ? 'electron-renderer' : 'electron-preload',
entry: [
'core-js',
'regenerator-runtime/runtime',
path.join(__dirname, '..', 'app/index.tsx'),
],
output: {
path: path.join(__dirname, '..', 'app/dist'),
publicPath: './dist/',
filename: 'renderer.prod.js',
},
module: {
rules: [
// Extract all .global.css to style.css as is
{
test: /\.global\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: './',
},
},
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
],
},
// Pipe other styles through css modules and append to style.css
{
test: /^((?!\.global).)*\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
sourceMap: true,
},
},
],
},
// Add SASS support - compile all .global.scss files and pipe it to style.css
{
test: /\.global\.(scss|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 1,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
// Add SASS support - compile all other .scss files and pipe it to style.css
{
test: /^((?!\.global).)*\.(scss|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]__[hash:base64:5]',
},
importLoaders: 1,
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
// WOFF Font
{
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// WOFF2 Font
{
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
},
// TTF Font
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
},
// EOT Font
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader',
},
// SVG Font
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml',
},
},
},
// Common Image Formats
{
test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/,
use: 'url-loader',
},
],
},
optimization: {
minimizer: process.env.E2E_BUILD
? []
: [
new TerserPlugin({
parallel: true,
sourceMap: true,
cache: true,
}),
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
map: {
inline: false,
annotation: true,
},
},
}),
],
},
plugins: [
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: false,
E2E_BUILD: false,
}),
new MiniCssExtractPlugin({
filename: 'style.css',
}),
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
],
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
internals/img/erb-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
internals/img/eslint.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
internals/img/jest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
internals/img/js-padded.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
internals/img/js.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
internals/img/npm.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
internals/img/react.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
internals/img/redux.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
internals/img/webpack.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
internals/img/yarn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1 @@
export default 'test-file-stub';

View File

@ -0,0 +1,8 @@
{
"rules": {
"no-console": "off",
"global-require": "off",
"import/no-dynamic-require": "off",
"import/no-extraneous-dependencies": "off"
}
}

View File

@ -0,0 +1,6 @@
const path = require('path');
require('@babel/register')({
extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'],
cwd: path.join(__dirname, '..', '..'),
});

View File

@ -0,0 +1,30 @@
// Check if the renderer and main bundles are built
import path from 'path';
import chalk from 'chalk';
import fs from 'fs';
const mainPath = path.join(__dirname, '..', '..', 'app', 'main.prod.js');
const rendererPath = path.join(
__dirname,
'..',
'..',
'app',
'dist',
'renderer.prod.js'
);
if (!fs.existsSync(mainPath)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
'The main process is not built yet. Build it by running "yarn build-main"'
)
);
}
if (!fs.existsSync(rendererPath)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
'The renderer process is not built yet. Build it by running "yarn build-renderer"'
)
);
}

View File

@ -0,0 +1,49 @@
import fs from 'fs';
import chalk from 'chalk';
import { execSync } from 'child_process';
import { dependencies } from '../../package.json';
if (dependencies) {
const dependenciesKeys = Object.keys(dependencies);
const nativeDeps = fs
.readdirSync('node_modules')
.filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`));
try {
// Find the reason for why the dependency is installed. If it is installed
// because of a devDependency then that is okay. Warn when it is installed
// because of a dependency
const { dependencies: dependenciesObject } = JSON.parse(
execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString()
);
const rootDependencies = Object.keys(dependenciesObject);
const filteredRootDependencies = rootDependencies.filter((rootDependency) =>
dependenciesKeys.includes(rootDependency)
);
if (filteredRootDependencies.length > 0) {
const plural = filteredRootDependencies.length > 1;
console.log(`
${chalk.whiteBright.bgYellow.bold(
'Webpack does not work with native dependencies.'
)}
${chalk.bold(filteredRootDependencies.join(', '))} ${
plural ? 'are native dependencies' : 'is a native dependency'
} and should be installed inside of the "./app" folder.
First, uninstall the packages from "./package.json":
${chalk.whiteBright.bgGreen.bold('yarn remove your-package')}
${chalk.bold(
'Then, instead of installing the package to the root "./package.json":'
)}
${chalk.whiteBright.bgRed.bold('yarn add your-package')}
${chalk.bold('Install the package to "./app/package.json"')}
${chalk.whiteBright.bgGreen.bold('cd ./app && yarn add your-package')}
Read more about native dependencies at:
${chalk.bold(
'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure'
)}
`);
process.exit(1);
}
} catch (e) {
console.log('Native dependencies could not be checked');
}
}

View File

@ -0,0 +1,16 @@
import chalk from 'chalk';
export default function CheckNodeEnv(expectedEnv) {
if (!expectedEnv) {
throw new Error('"expectedEnv" not set');
}
if (process.env.NODE_ENV !== expectedEnv) {
console.log(
chalk.whiteBright.bgRed.bold(
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
)
);
process.exit(2);
}
}

View File

@ -0,0 +1,16 @@
import chalk from 'chalk';
import detectPort from 'detect-port';
const port = process.env.PORT || '1212';
detectPort(port, (err, availablePort) => {
if (port !== String(availablePort)) {
throw new Error(
chalk.whiteBright.bgRed.bold(
`Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 yarn dev`
)
);
} else {
process.exit(0);
}
});

View File

@ -0,0 +1,5 @@
if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
console.warn(
"\u001b[33mYou don't seem to be using yarn. This could produce unexpected results.\u001b[39m"
);
}

View File

@ -0,0 +1,7 @@
import path from 'path';
import rimraf from 'rimraf';
export default function deleteSourceMaps() {
rimraf.sync(path.join(__dirname, '../../app/dist/*.js.map'));
rimraf.sync(path.join(__dirname, '../../app/*.js.map'));
}

View File

@ -0,0 +1,22 @@
import path from 'path';
import { execSync } from 'child_process';
import fs from 'fs';
import { dependencies } from '../../app/package.json';
const nodeModulesPath = path.join(__dirname, '..', '..', 'app', 'node_modules');
if (
Object.keys(dependencies || {}).length > 0 &&
fs.existsSync(nodeModulesPath)
) {
const electronRebuildCmd =
'../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .';
const cmd =
process.platform === 'win32'
? electronRebuildCmd.replace(/\//g, '\\')
: electronRebuildCmd;
execSync(cmd, {
cwd: path.join(__dirname, '..', '..', 'app'),
stdio: 'inherit',
});
}

22853
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

345
package.json Normal file
View File

@ -0,0 +1,345 @@
{
"name": "deskrin",
"productName": "Deskrin",
"version": "0.0.1",
"description": "TODO: write description of this app",
"scripts": {
"build": "concurrently \"yarn build-main\" \"yarn build-renderer\"",
"build-dll": "cross-env NODE_ENV=development webpack --config ./configs/webpack.config.renderer.dev.dll.babel.js --colors",
"build-e2e": "cross-env E2E_BUILD=true yarn build",
"build-main": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.main.prod.babel.js --colors",
"build-renderer": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
"dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && cross-env START_HOT=1 yarn start-renderer-dev",
"coverage": "cross-env BABEL_DISABLE_CACHE=1 jest --coverage",
"electron-rebuild": "electron-rebuild --parallel --force --types prod,dev,optional --module-dir app",
"lint": "cross-env NODE_ENV=development eslint . --cache --ext .js,.jsx,.ts,.tsx",
"lint-fix": "yarn --silent lint --fix; exit 0",
"lint-styles": "stylelint --ignore-path .eslintignore '**/*.*(css|scss)' --syntax scss",
"lint-styles-fix": "yarn --silent lint-styles --fix; exit 0",
"package": "yarn build && electron-builder build --publish never",
"package-all": "yarn build && electron-builder build -mwl",
"package-ci": "yarn postinstall && yarn build && electron-builder --publish never",
"package-mac": "yarn build && electron-builder build --mac",
"package-linux": "yarn build && electron-builder build --linux",
"package-win": "yarn build && electron-builder build --win --x64",
"postinstall": "node -r @babel/register internals/scripts/CheckNativeDep.js && electron-builder install-app-deps && yarn build-dll && opencollective-postinstall",
"postlint-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{js,jsx,json,html,css,less,scss,yml}'",
"postlint-styles-fix": "prettier --ignore-path .eslintignore --single-quote --write '**/*.{css,scss}'",
"preinstall": "node ./internals/scripts/CheckYarn.js",
"prestart": "yarn build",
"start": "cross-env NODE_ENV=production electron ./app/main.prod.js",
"start-main-debug": "yarn start-main-dev --inspect=5858 --remote-debugging-port=9223",
"start-main-dev": "cross-env START_HOT=1 NODE_ENV=development electron -r ./internals/scripts/BabelRegister ./app/main.dev.ts",
"start-renderer-dev": "cross-env NODE_ENV=development webpack-dev-server --config configs/webpack.config.renderer.dev.babel.js",
"test": "cross-env BABEL_DISABLE_CACHE=1 jest",
"test-all": "yarn lint && yarn tsc && yarn build && yarn test",
"test-e2e": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe electron:./app ./test/e2e/HomePage.e2e.ts",
"test-e2e-live": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe --live electron:./app ./test/e2e/HomePage.e2e.ts",
"test-watch": "yarn test --watch"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"cross-env NODE_ENV=development eslint --cache"
],
"{*.json,.{babelrc,eslintrc,prettierrc,stylelintrc}}": [
"prettier --ignore-path .eslintignore --parser json --write"
],
"*.{css,scss}": [
"stylelint --ignore-path .eslintignore --syntax scss --fix",
"prettier --ignore-path .eslintignore --single-quote --write"
],
"*.{html,md,yml}": [
"prettier --ignore-path .eslintignore --single-quote --write"
]
},
"build": {
"productName": "Deskrin",
"appId": "com.pavlobu.Deskrin",
"files": [
"dist/",
"node_modules/",
"app.html",
"main.prod.js",
"main.prod.js.map",
"package.json"
],
"dmg": {
"contents": [
{
"x": 130,
"y": 220
},
{
"x": 410,
"y": 220,
"type": "link",
"path": "/Applications"
}
]
},
"win": {
"target": [
"nsis",
"msi"
]
},
"linux": {
"target": [
"deb",
"rpm",
"AppImage"
],
"category": "Development"
},
"directories": {
"buildResources": "resources",
"output": "release"
},
"publish": {
"provider": "github",
"owner": "pavlobu",
"repo": "deskrin",
"private": false
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/pavlobu/deskrin.git"
},
"author": {
"name": "Pavlo (Paul) Buidenkov",
"email": "pavlobu@gmail.com",
"url": "https://github.com/pavlobu/deskrin"
},
"contributors": [
{
"name": "Pavlo (Paul) Buidenkov",
"email": "pavlobu@gmail.com",
"url": "https://github.com/pavlobu/deskrin"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/pavlobu/deskrin"
},
"keywords": [
"electron",
"react",
"redux",
"typescript",
"ts",
"sass",
"webpack",
"hot",
"reload"
],
"homepage": "https://github.com/pavlobu/deskrin#readme",
"jest": {
"testURL": "http://localhost/",
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/fileMock.js",
"\\.(css|less|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"js",
"jsx",
"ts",
"tsx",
"json"
],
"moduleDirectories": [
"node_modules",
"app/node_modules"
],
"setupFiles": [
"./internals/scripts/CheckBuildsExist.js"
],
"collectCoverageFrom": [
"**/*.{ts,tsx}",
"!**/node_modules/**",
"!**/dist/**",
"!**/dll/**",
"!**/internals/**",
"!**/coverage/**",
"!**/configs/**",
"!**/resources/**"
],
"testResultsProcessor": "jest-sonar-reporter"
},
"devDependencies": {
"@amilajack/testcafe-browser-provider-electron": "^0.0.15-alpha.1",
"@babel/core": "^7.11.1",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-decorators": "^7.10.5",
"@babel/plugin-proposal-do-expressions": "^7.10.4",
"@babel/plugin-proposal-export-default-from": "^7.10.4",
"@babel/plugin-proposal-export-namespace-from": "^7.10.4",
"@babel/plugin-proposal-function-bind": "^7.10.5",
"@babel/plugin-proposal-function-sent": "^7.10.4",
"@babel/plugin-proposal-json-strings": "^7.10.4",
"@babel/plugin-proposal-logical-assignment-operators": "^7.11.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
"@babel/plugin-proposal-numeric-separator": "^7.10.4",
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
"@babel/plugin-proposal-pipeline-operator": "^7.10.5",
"@babel/plugin-proposal-throw-expressions": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-transform-react-constant-elements": "^7.10.4",
"@babel/plugin-transform-react-inline-elements": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@babel/preset-typescript": "^7.10.4",
"@babel/register": "^7.10.5",
"@types/enzyme": "^3.10.5",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/express": "^4.17.7",
"@types/history": "^4.7.6",
"@types/jest": "^26.0.5",
"@types/node": "12",
"@types/react": "^16.9.44",
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",
"@types/react-router": "^5.1.8",
"@types/react-router-dom": "^5.1.5",
"@types/react-test-renderer": "^16.9.2",
"@types/redux-logger": "^3.0.8",
"@types/webpack": "^4.41.21",
"@types/webpack-env": "^1.15.2",
"@typescript-eslint/eslint-plugin": "^3.6.1",
"@typescript-eslint/parser": "^3.6.1",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.1.0",
"babel-loader": "^8.1.0",
"babel-plugin-dev-expression": "^0.2.2",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"browserslist-config-erb": "^0.0.1",
"chalk": "^4.1.0",
"concurrently": "^5.2.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.0",
"css-loader": "^3.6.0",
"detect-port": "^1.3.0",
"electron": "^8",
"electron-builder": "^22.3.6",
"electron-devtools-installer": "^2.2.4",
"electron-rebuild": "^1.10.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.5.0",
"eslint": "^7.5.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-airbnb-typescript": "^9.0.0",
"eslint-config-erb": "^1.0.0",
"eslint-config-prettier": "^6.11.0",
"eslint-import-resolver-webpack": "^0.12.2",
"eslint-plugin-compat": "^3.8.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^23.18.0",
"eslint-plugin-jsx-a11y": "6.3.1",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react-hooks": "^4.0.8",
"eslint-plugin-testcafe": "^0.2.1",
"file-loader": "^6.0.0",
"husky": "^4.2.5",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.1.0",
"jest-sonar-reporter": "^2.0.0",
"lint-staged": "^10.2.11",
"mini-css-extract-plugin": "^0.9.0",
"opencollective-postinstall": "^2.0.3",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"prettier": "^2.0.5",
"react-test-renderer": "^16.12.0",
"redux-logger": "^3.0.6",
"rimraf": "^3.0.0",
"sass-loader": "^9.0.2",
"style-loader": "^1.2.1",
"stylelint": "^13.6.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^20.0.0",
"terser-webpack-plugin": "^3.0.7",
"testcafe": "^1.8.8",
"testcafe-browser-provider-electron": "^0.0.15",
"testcafe-react-selectors": "^4.0.0",
"ts-jest": "^26.1.4",
"typescript": "^3.9.7",
"typings-for-css-modules-loader": "^1.7.0",
"url-loader": "^4.1.0",
"webpack": "^4.43.0",
"webpack-bundle-analyzer": "^3.8.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.0.9"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.14.0",
"@hot-loader/react-dom": "^16.13.0",
"@reduxjs/toolkit": "^1.4.0",
"axios": "^0.19.2",
"connected-react-router": "^6.6.1",
"electron-debug": "^3.1.0",
"electron-log": "^4.2.2",
"electron-updater": "^4.3.1",
"express": "^4.17.1",
"get-port": "^5.1.1",
"history": "^4.7.2",
"react": "^16.13.1",
"react-dom": "^16.12.0",
"react-hot-loader": "^4.12.21",
"react-redux": "^7.2.0",
"react-router-dom": "^5.2.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"regenerator-runtime": "^0.13.5",
"source-map-support": "^0.5.19"
},
"devEngines": {
"node": ">=7.x",
"npm": ">=4.x",
"yarn": ">=0.21.3"
},
"collective": {
"url": "TODO: add collective page"
},
"browserslist": [],
"prettier": {
"overrides": [
{
"files": [
".prettierrc",
".babelrc",
".eslintrc",
".stylelintrc"
],
"options": {
"parser": "json"
}
}
],
"singleQuote": true
},
"stylelint": {
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier"
]
},
"renovate": {
"extends": [
"bliss"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"jestSonar": {
"reportPath": "test-reports",
"reportFile": "test-reporter.xml",
"indent": 4
}
}

BIN
resources/icon.icns Normal file

Binary file not shown.

BIN
resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
resources/icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show More