extensions : gui renderer

This commit is contained in:
babayaga 2025-07-04 20:18:13 +02:00
parent e903511d52
commit 48239801ce
59 changed files with 13191 additions and 0 deletions

View File

@ -0,0 +1,2 @@
*.scss linguist-detectable=false
*.sass linguist-detectable=false

View File

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: guasam
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

86
packages/kbot/extensions/gui/.gitignore vendored Normal file
View File

@ -0,0 +1,86 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
.DS_Store
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Webpack
.webpack/
# Electron-Forge
out/

View File

@ -0,0 +1,5 @@
{
"singleQuote": true,
"trailingComma": "all",
"jsxSingleQuote": true
}

View File

@ -0,0 +1,567 @@
# Change Log
All notable changes to the project are listed here.
For more information visit:
https://github.com/codesbiome/electron-react-webpack-typescript-2024
<br>
### v8.1.0
- 🎉 Electron version upgraded `v23.0.0`.
- Using `eslint.config.json` as eslint configuration.
- Tweaked app themes colors.
- Upgraded outdated packages:
| Package | Version |
| ------------------------------------ | --------- |
| electron | `^31.2.1` |
| @electron-forge | `7.4.0` |
| electron-squirrel-startup | `^1.0.1` |
| @pmmmwh/react-refresh-webpack-plugin | `^0.5.15` |
| @typescript-eslint | `^7.16.1` |
| css-loader | `^7.1.2` |
| eslint | `^9.7.0` |
| eslint-plugin-react | `^7.34.4` |
| react-refresh | `^0.14.2` |
| sass | `^1.77.8` |
| sass-loader | `^14.2.1` |
| style-loader | `^4.0.0` |
| typescript | `^5.5.3` |
| webpack | `^5.93.0` |
| react | `^18.3.1` |
| react-dom | `^18.3.1` |
<br>
### v8.0.0
- 🎉 Application UI and Themes (light/dark).
- Using latest Electron version `v28`
- Changed app accent colors & added credits menu item.
- Integrated `electron-window` components & modules in project's file structure.
- Separated dark/light themes from application stylesheet for easy modification.
- Added `@styles` alias for easily import stylesheets.
- Removed `less-loader` by default from project.
- Removed unused `misc` directory.
- Removed unused `src/common` directory.
- Converted `less` to `scss` for window components stylesheet.
- Updated forge config with more useful hints.
- Upgraded outdated packages to their latest supported versions.
<br>
### v7.8.0
Upgraded outdated packages:
| Package | Version |
| ------------------------------ | -------- |
| electron | `27.1.2` |
| @electron-forge | `7.1.0` |
| @typescript-eslint | `6.13.1` |
| eslint-plugin-import | `2.29.0` |
| eslint | `8.54.0` |
| less | `4.2.0` |
| sass | `1.69.5` |
| ts-loader | `9.5.1` |
| typescript | `5.3.2` |
| webpack | `5.89.0` |
| react-refresh-webpack-plugin | `0.5.11` |
| fork-ts-checker-webpack-plugin | `9.0.2` |
<br>
### v7.7.0
Upgraded outdated packages:
| Package | Version |
| ---------------------------- | -------- |
| electron | `26.2.2` |
| @electron-forge | `6.4.2` |
| @typescript-eslint | `6.7.3` |
| eslint-plugin-import | `2.28.1` |
| eslint-plugin-react | `7.33.2` |
| eslint | `8.50.0` |
| less | `4.2.0` |
| sass | `1.68.0` |
| typescript | `5.2.2` |
| webpack | `5.88.2` |
| react-refresh-webpack-plugin | `0.5.11` |
<br>
### v7.6.0
Upgraded outdated packages:
| Package | Version |
| ------------------ | -------- |
| electron | `25.2.0` |
| @electron-forge | `6.2.1` |
| @typescript-eslint | `6.0.0` |
| eslint | `8.44.0` |
| less-loader | `11.1.3` |
| sass | `1.63.6` |
| sass-loader | `13.3.2` |
| ts-loader | `9.4.4` |
| typescript | `5.1.6` |
| webpack | `5.88.1` |
<br>
### v7.5.0
Upgraded outdated packages:
| Package | Version |
| ------------------ | -------- |
| electron | `25.0.1` |
| @typescript-eslint | `5.59.9` |
| css-loader | `6.8.1` |
| eslint | `8.42.0` |
| less-loader | `11.1.2` |
| sass | `1.62.1` |
| sass-loader | `13.3.1` |
| style-loader | `3.3.3` |
| ts-loader | `9.4.3` |
| typescript | `5.1.3` |
| webpack | `5.85.1` |
<br>
### v7.3.3
Upgraded outdated packages:
| Package | Version | |
| ------------------ | -------- | --- |
| electron | `24.1.2` | ⬆️ |
| @electron-forge | `6.1.1` | ⬆️ |
| @typescript-eslint | `5.59.0` | ⬆️ |
| eslint | `8.39.0` | ⬆️ |
| sass | `1.62.0` | ⬆️ |
| sass-loader | `13.2.2` | ⬆️ |
| typescript | `5.0.4` | ⬆️ |
| webpack | `5.80.0` | ⬆️ |
<br>
### v7.3.2
Upgraded outdated packages:
| Package | Version | |
| ------------------ | ---------- | --- |
| electron | `23.2.0` | ⬆️ |
| eslint | `8.36.0` | ⬆️ |
| sass | `1.60.0` | ⬆️ |
| sass-loader | `13.2.1` | ⬆️ |
| style-loader | `3.3.2` | ⬆️ |
| typescript | `5.0.2` | ⬆️ |
| webpack | `5.76.3` | ⬆️ |
| @types/node | `18.15.10` | ⬆️ |
| @types/react | `18.0.29` | ⬆️ |
| @types/react-dom | `18.0.11` | ⬆️ |
| @typescript-eslint | `5.56.0` | ⬆️ |
<br>
### v7.3.1
Upgraded outdated packages:
| Package | Version | |
| ------------------ | --------- | --- |
| electron | `23.1.2` | ⬆️ |
| eslint | `8.35.0` | ⬆️ |
| sass | `1.58.3` | ⬆️ |
| @types/node | `18.14.6` | ⬆️ |
| @types/react | `18.0.28` | ⬆️ |
| @types/react-dom | `18.0.11` | ⬆️ |
| @typescript-eslint | `5.54.0` | ⬆️ |
<br>
### v7.3.0
- 🎉 Electron version upgraded `v23.0.0`
- Upgraded outdated packages:
- `electron` upgraded to `v23.0.0`
- `@electron-forge` deps upgraded to `v6.0.5`
- `@typescript-eslint` deps upgraded to `v5.51.0`
- `css-loader` upgraded to `v6.7.3`
- `eslint` upgraded to `v8.33.0`
- `eslint-plugin-import` upgraded to `v2.27.5`
- `eslint-plugin-react` upgraded to `v7.32.2`
- `fork-ts-checker-webpack-plugin` upgraded to `v7.3.0`
- `sass` upgraded to `v1.58.0`
- `typescript` upgraded to `v4.9.5`
<br>
### v7.2.0
- 🎉 Electron version upgraded `v22.0.0`
- Upgraded outdated packages:
- `electron` upgraded to `v22.0.0`
- `@electron-forge` deps upgraded to `v6.0.4`
- `@pmmmwh/react-refresh-webpack-plugin` upgraded to `v0.5.10`
- `@typescript-eslint` deps upgraded to `v5.46.0`
- `css-loader` upgraded to `v6.7.2`
- `eslint` upgraded to `v8.29.0`
- `sass-loader` upgraded to `v13.2.0`
- `ts-loader` upgraded to `v9.4.2`
- `typescript` upgraded to `v4.9.4`
- `webpack` upgraded to `v5.75.0`
<br>
### v7.1.0
- 🎉 Electron version upgraded to `v21.2.0`
- Fixed Devtools Console warning message caused by content policy.
- Upgraded forge config plugins format to support latest version.
- Disabled `sandbox` by default in application window.
- Upgraded outdated deps:
- `electron` upgraded to `v21.2.0`
- `@electron-forge` deps upgraded to `v6.0.0-beta.68`
- `@pmmmwh/react-refresh-webpack-plugin` upgraded to `v0.5.8`
- `@typescript-eslint` deps upgraded to `v5.41.0`
- `classnames` upgraded to `v2.3.2`
- `eslint` upgraded to `v8.26.0`
- `eslint-plugin-react` upgraded to `v7.31.10`
- `less-loader` upgraded to `v11.1.0`
- `sass` upgraded to `v1.55.0`
- `sass-loader` upgraded to `v13.1.0`
- `ts-loader` upgraded to `v9.4.1`
- `typescript` upgraded to `v4.8.4`
<br>
### v7.0.0
- 🥳 New layout for default application.
- 🤖 Overhaul for dark/light themes with new colors.
- Improved transition timing of title menus list.
- Fixed native modules compiling issue with update to related webpack loader.
- Updated forge `devContentSecurityPolicy` config for electron window.
- Upgraded outdated deps:
- `electron` upgraded to `v19.0.14`
- `@electron-forge` deps upgraded to `v6.0.0-beta.65`
- `@typescript-eslint` deps upgraded to `v5.36.1`
- `eslint` upgraded to `v8.23.0`
- `eslint-plugin-react` upgraded to `v7.30.1`
- `sass` upgrded to `v1.54.0`
- `typescript` upgraded to `v4.7.4`
<br>
### v6.2.0
- Upgraded outdated deps:
- `electron` upgraded to `^19.0.9`.
- `@typescript-eslint` deps upgraded to `v5.30.7`.
- `eslint` upgraded to `v8.20.0"`.
- `fork-ts-checker-webpack-plugin` upgraded to `v7.2.13`.
- `sass` upgraded to `v1.54.0`.
- `sass-loader` upgraded to `v13.0.2`.
- `webpack` upgraded to `v5.74.0`.
<br>
### v6.1.0
- 🎉 Electron version upgraded to `v19.0.6`
- Using `misc/window` for custom window without git submodule.
- Upgraded outdated deps:
- `electron` upgraded to `v19.0.6`
- `@electron-forge` deps upgraded to `v6.0.0-beta.64`
- `@pmmmwh/react-refresh-webpack-plugin` upgraded to `v0.5.7`
- `@types` deps upgraded to latest version
- `@typescript-eslint` deps upgraded to `v5.29.0`
- `eslint` upgraded to `v8.18.0`
- `eslint-plugin-react` upgraded to `v7.30.1`
- `fork-ts-checker-webpack-plugin` upgraded to `v7.2.11`
- `less` upgraded to `v4.1.3`
- `less-loader` upgraded to `v11.0.0`
- `react-refresh` upgraded to `v0.14.0`
- `sass` upgraded to `v1.53.0`
- `sass-loader` upgraded to `v13.0.1`
- `ts-loader` upgraded to `v9.3.1`
- `typescript` upgraded to `v4.7.4`
- `webpack` upgraded to `5.73.0`
<br>
### v6.0.0
- 🙌🏻 New Layout for default application.
- 🌑 Dark mode & 💡 Light Mode colors.
- 🎉 Electron version upgraded to `v18.1.0`
- Using `sass/scss` stylesheets by default for project (previously `less` was used).
- Using `React Fast Refresh` for hot reloading, removed old `hot-loader`.
- Titlebar Menus style overrides for improvements with rounded corners.
- Created a new `Theme.scss` file for adjusting light/dark mode color schemes.
- Persist theme state in `localStorage` by default.
- Using `pnpm` instead of `yarn` as package manager for project.
- Upgraded outdated deps:
- `electron` upgraded to `v18.1.0`
- `eslint` upgraded to `v8.13.0`
- `typescript` upgraded to `v4.6.3`
- `webpack` upgraded to `v5.72.0`
- `react` deps upgraded to `v18.0.0`
<br>
### v5.5.0
- Upgraded outdated deps:
- `electron` upgraded to `v17.2.0`
- `eslint` ugpraded to `v8.11.0`,
- `css-loader` upgraded to `v6.7.1`
- `@typescript-eslint/eslint-plugin` deps upgraded to `v5.16.0`
- `eslint-plugin-react` upgraded to `v7.29.4`
- `ts-loader` upgraded to `v9.2.8`
- `typescript` upgraded to `v4.6.3`
- `webpack` upgraded to `v5.70.0`
<br>
### v5.4.0
- 🎉 Electron core upgraded `v17.0.1`
- Upgraded outdated deps:
- `@hot-loader/react-dom` upgraded to `v17.0.2`
- `webpack` upgraded to `v5.69.1`
- `typescript` upgraded to `v4.5.5`
- `fork-ts-checker-webpack-plugin` upgraded to `v7.2.1`
- `eslint` upgraded to `v8.9.0`
- `css-loader` upgraded to `v6.6.0`
- `@typescript-eslint` deps upgraded to `v5.12.1`
<br>
### v5.3.0
- Electron Window : File menu visible by default
- Upgraded outdated deps:
- `electron` upgraded to `v16.0.7`
- `@electron-forge` deps upgraded to `v6.0.0-beta.63`
- `@types/node` upgraded to `v17.0.8`
- `@typescript-eslint` deps upgraded to `v5.9.1`
- `eslint` upgraded to `v8.6.0`
- `typescript` upgraded to `v4.5.4`
- `webpack` upgraded to `v5.66.0`
<br>
### v5.2.0
- 🎉 Electron core upgraded `v16`
- Upgraded outdated deps:
- `@typescript-eslint` deps upgraded to `^5.5.0`
- `eslint` upgraded to `^8.4.0`
- `fork-ts-checker-webpack-plugin` upgraded to `^6.5.0`
- `typescript` upgraded to `^4.5.2`
- `webpack` upgraded to `^5.64.4`
<br>
### v5.1.0
- Fix: CSS/LESS `background-image` corrupted image file output.
- Updated: Webpack Rules to load assets using [Webpack v5 Asset Modules](https://webpack.js.org/guides/asset-modules/) instead of `file-loader`
- Fix: Typo in eslint alias map for `@components`
- Updated: Window (submodule) to latest version.
- Removed: Unused contextBridge api declaration.
<br>
### v5.0.0
- Overhauled: Application default layout and styling.
- Overhauled: Project files structure to separate 'main' & 'renderer' modules.
- Added: Custom Window Frame.
- Added: Custom Window Titlebar.
- Added: Custom Menus for Titlebar.
- Added: Window controls for `windows` & `mac` based platform.
- Renamed: `.eslintrc.json` to `.eslintrc`
- Upgraded Outdated deps :
- `eslint` upgraded to `v8.2.0`
- `css-loader` upgraded to `v6.5.1`
- `@typescript-eslint` deps upgraded to `v5.3.0`
- `webpack` upgraded to `v5.62.1`
<br>
### v4.2.0
- 🎉 Electron core upgraded to version `v15`
- Application colors updated for vue environment
- Fix eslint script
- Default window background color updated.
- Upgrade outdated deps:
- `electron` upgraded to `^15.0.0`
- `@electron-forge` deps upgraded to `6.0.0-beta.61`
- `@types/node` upgraded to `^16.9.6`
- `@typescript-eslint` deps upgraded to `^4.31.2`
- `css-loader` upgraded to `^6.3.0`
<br>
### v4.1.0
- 🎉 Electron core upgraded to version `v14`
- Update application style properties
- Enable `nativeWindowOpen` for main window
- Remove `enableRemoteModule` from main window
- Fix : Hot reloading issue caused by `liveReload` in webpack devServer
- Added additional Webpack `devServer` configuration in `tools/forge/forge.config.js`
- Upgraded outdated deps:
- `@electron-forge` deps upgraded to `6.0.0-beta.60`
- `@typescript-eslint` deps upgraded to `^4.30.0`
- `@types/react` upgraded to `^17.0.19`
- `electron` upgraded to `^14.0.0`
- `eslint-plugin-import` upgraded to `^2.24.2`
- `eslint-plugin-react` upgraded to `^7.25.1`
- `typescript` upgraded to `^4.4.2`
- `webpack` upgraded to `^5.51.1`
<br>
### v4.0.1
- Update file-loader configuration for `assets` files
- Add packager configuration for app executable file details
- Update `README` with similar useful projects
<br>
### v4.0.0
- Overhaul for Application default layout and styling.
- Default window background color updated.
- Default `minimal` stats output for main & renderer process via webpack.
- Upgraded outdated deps :
- `electron` upgraded to `^13.1.9`
- `@electron-forge` packages upgraded to `6.0.0-beta.59`
- `@typescript-eslint` packages upgraded to `^4.29.2`
- `css-loader` upgraded to `^6.2.0`
- `eslint` upgraded to `^7.32.0`
- `fork-ts-checker-webpack-plugin` upgraded to `^6.3.2`
- `less-loader` upgraded to `10.0.1`
- `style-loader` upgraded to `^3.2.1`
- `ts-loader` upgraded to `9.2.5`
- `typescript` upgraded to `^4.3.5`
- `webpack` upgraded to `^5.50.0`
<br>
### v3.1.0
- Electron core 🚀 upgraded to version 13.
- Expose Webpack Ports settings in forge configuration.
- Upgraded outdated packages :
- `electron` upgraded to `^13.0.1`
- `@typescript-eslint` packages upgraded to `^4.26.0`
- `eslint` upgraded to `^7.27.0`
- `css-loader` upgraded to `^5.2.6`
- `ts-loader` upgraded to `8.3.0`
- `typescript` upgraded to `^4.3.2`
- `webpack` upgraded to `^5.38.1`
- `fork-ts-checker-webpack-plugin` upgraded to `^6.2.10`
<br>
### v3.0.1
- Upgraded outdated packages
- `electron'` upgraded to `^12.0.6`
- `react` upgraded to `^17.0.2`
- `react-dom` upgraded to `^17.0.2`
- `css-loader` upgraded to `^5.2.4`
- `eslint` upgraded to `^7.25.0`
- `node-loader` upgraded to `2.0.0`
- `ts-loader` upgraded to `8.2.0`
- `typescript` upgraded to `^4.2.4`
- `webpack` upgraded to `^5.36.2`
<br>
### v3.0.0
- Overhaul for Application component layout and styling.
- Project Files structure updated.
- Move static images to `assets` directory.
- Remove `.prettierignore` file.
- Use `.tsx` file extension for `preload` and `renderer` incase we need to use components.
- Introduce new `assets` webpack alias.
- Modify aliases usage for new project structure.
- Upgraded outdated dependencies
- `electron` upgraded to `12.0.1`
- `css-loader` upgraded to `5.1.3`
- `eslint` upgraded to `7.22.0`
- `less` upgraded to `4.1.1`
- `less-loader` upgraded to `7.3.0`
- `ts-loader` upgraded to `8.0.18`
- `typescript` upgraded to `4.2.3`
- `webpack` upgraded to `5.27.1`
<br>
### v2.1.0
- New Year 2021 🎉🎊
- Upgraded outdated dependencies
- `electron` version upgraded to `11.1.1`
- `react` version upgraded to `17.0.1`
- `hot-loader` version upgraded to `17.0.1`
- `webpack` version upgraded to `5.13.0`
- `typescript` version upgraded to `4.1.3`
- `ts-loader` version upgraded to `8.0.14`
- `css-loader` version upgraded to `5.0.1`
- `style-loader` version upgraded to `2.0.0`
- `less` version upgraded to `4.1.0`
<br>
### v2.0.2
- Upgraded outdated dependencies
- `electron` version upgraded to `10.x`
- `typescript` version upgraded to `4.x`
- `less-loader` version upgraded to `7.x`
<br>
### v2.0.1
- Upgraded outdated dependencies
<br>
### v2.0.0
- Added electron window background color
- Devtools opening on startup is disabled
- Added `preload` script usage (preload.ts) 👍
- Moved webpack `aliases` to separate file
- Added new style & color changes to boilerplate layout
- Added prettier configuration files `.prettierrc` `.prettierignore`
- `contextIsolation` is enabled by default
- `nodeIntegration` `enableRemoteModule` `nodeIntegrationInWorker` `nodeIntegrationInSubFrames` are disabled default
<br>
### v1.0.0
- Upgrade package dependencies to latest
- Add hot module replacement (live reload)
- Add linting via ESLint
- Custom webpack configuration
- Custom forge configuration for package/bundle
- Add aliases for project paths
- Image loader to display images

View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible 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.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders 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, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Repository Discussions.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@ -0,0 +1,19 @@
# Contributing to ERWT
Thank you for investing your time in contributing to our project!
Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
<br>
## How to Contribute?
You can contribute to our project by providing `features/bugfixes/improvements` related Pull Requests.
<br>
Just make sure to test all the changes you provide before submission anything into this project.
<br>
## Having a question about this project?
Feel free to use [Discussions](https://github.com/codesbiome/electron-react-webpack-typescript-2022/discussions) to ask any questions related to this project.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Codesbiome
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.

View File

@ -0,0 +1,177 @@
# Electron React Webpack Typescript (Custom Titlebar)
A prebuilt project for creating desktop apps using Electron, React, Webpack & Typescript with hot-reload, easy to use custom import aliases & executable builds for distribution.
<br>
<img src="assets/images/anim_v8.gif" />
<br>
Special thanks to [@guasam](https://github.com/guasam) for development of Custom Window, Titlebar, UI/UX etc.
<br>
## Core Features
- 🌟 Electron
- 🌀 TypeScript
- ⚛️ React
- 🥗 SASS/SCSS Loader
- 🎨 CSS Loader
- 📸 Image Loader
- 🆎 Font Loader
- 🧹 ESLint
- 📦 Electron Forge
- 📐 Custom Window Frame
- 📐 Custom Window Titlebar
- 📐 Custom Window Menubar
- 🔱 Webpack & Configuration
- 🧩 Aliases for Project Paths
- 🗡️ Native (node) Modules Support
- 🔥 React Fast Refresh + Webpack HMR
- 🌞 Dark Mode + Light Mode (Theme)
- 🎁 Package Bundling (Distribution / Release)
<br>
## Custom Electron Window Titlebar & Menus
This project includes [electron-window](https://github.com/guasam/electron-window) as core of custom window components and modules.
**Following are the list of features it provides :**
- Custom Titlebar for Electron Window.
- Easily changable platform specific controls for max/min/close buttons using `windows` or `mac` value for `platform` property with `<WindowFrame>` in renderer.
- Titlebar menus can show/hide by pressing `alt` or `option` key.
- Window frame `title` prop displays in titlebar center when menus are toggeled off.
- Menu entries can be customized in `src/main/window/titlebarMenus.ts` file.
- Menu items and windows controls UI or colors can be customized easily by modifying the `src/renderer/window` components & styles.
<br>
### Custom Aliases for Paths
We can use predefined aliases for `import` paths already used in this project. Following are the details:
| Alias | Target Path |
| ------------- | -------------------------- |
| `@assets` | `/assets` |
| `@main` | `/src/main` |
| `@renderer` | `/src/renderer` |
| `@common` | `/src/common` |
| `@src` | `/src` |
| `@styles` | `/src/renderer/styles` |
| `@components` | `/src/renderer/components` |
<br>
### Want to use Vite instead of Webpack bundler?
Introducing the [ElectroVite](https://github.com/guasam/electrovite-react) project with a brief description below.
<br>
## Installation
![status](https://img.shields.io/badge/ERWT-Main%20Version-blue.svg)
Main version of this project contains files structure in separate context for `main` and `renderer`, with custom electron window, titlebar etc.
```bash
git clone https://github.com/codesbiome/electron-react-webpack-typescript-2024
```
<br>
<div align="center">
<b>OR</b>
</div>
<br>
![status](https://img.shields.io/badge/ERWT-Minimal%20Version-0a922a.svg)
Minimal version of ERWT contains very simple project files structure, no custom window, no custom titlebar & menus.
```bash
git clone -b minimal https://github.com/codesbiome/electron-react-webpack-typescript-2024
```
<br>
Install dependencies using [pnpm](https://pnpm.io/) or [yarn](https://www.npmjs.com/package/yarn) or [npm](https://www.npmjs.com/) :
```bash
# using pnpm
pnpm install
# or using yarn
yarn install
# or using npm
npm install
```
<br />
## Start : Development
To develop and run your application, you need to run following command.
<br />
Start electron application for development :
```bash
yarn start
```
<br />
## Lint : Development
To lint application source code using ESLint via this command :
```bash
yarn lint
```
<br />
## Package : Production
Customize and package your Electron app with OS-specific bundles (.app, .exe etc)
```bash
yarn package
```
<br />
## Make : Production
Making is a way of taking your packaged application and making platform specific distributables like DMG, EXE, or Flatpak files (amongst others).
```bash
yarn make
```
<br />
## Publish : Production
Publishing is a way of taking the artifacts generated by the `make` command and sending them to a service somewhere for you to distribute or use as updates. (This could be your update server or an S3 bucket)
```bash
yarn publish
```
<br />
## Packager & Makers Configuration
This provides an easy way of configuring your packaged application and making platform specific distributables like DMG, EXE, or Flatpak files.
This configurations file is available in :
```bash
tools/forge/forge.config.js
```
For further information, you can visit [Electron Forge Configuration](https://www.electronforge.io/configuration)

View File

@ -0,0 +1,3 @@
# Attribution
<a href="https://www.flaticon.com/free-icons/license" title="license icons">Thanks to Flaticon</a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,18 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:react/recommended"],
"parser": "@typescript-eslint/parser",
"settings": {
"react": {
"version": "latest"
}
},
"rules": {
"react/prop-types": "off",
"@typescript-eslint/no-var-requires": "off"
}
}

View File

@ -0,0 +1,90 @@
{
"name": "erwt",
"productName": "ERWT",
"version": "8.1.0",
"description": "Robust project for developing Desktop Application with Electron, React, Webpack & TypeScript.",
"main": ".webpack/main",
"scripts": {
"start": "cross-env NODE_ENV=development electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint src/ --ext .ts,.js,.tsx,.jsx"
},
"keywords": [
"electron boilerplate",
"minimal",
"electron-webpack",
"electron-react",
"electron-typescript",
"hmr",
"boilerplate",
"2024",
"ERWT"
],
"author": {
"name": "codesbiome",
"url": "https://github.com/codesbiome"
},
"contributors": [
{
"name": "guasam",
"url": "https://github.com/guasam"
}
],
"repository": {
"type": "git",
"url": "https://github.com/codesbiome/electron-react-webpack-typescript-2024"
},
"license": "MIT",
"config": {
"forge": "./tools/forge/forge.config.js"
},
"devDependencies": {
"@electron-forge/cli": "7.4.0",
"@electron-forge/maker-deb": "7.4.0",
"@electron-forge/maker-rpm": "7.4.0",
"@electron-forge/maker-squirrel": "7.4.0",
"@electron-forge/maker-zip": "7.4.0",
"@electron-forge/plugin-webpack": "7.4.0",
"@marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
"@types/node": "^20.14.11",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/webpack-env": "^1.18.5",
"@typescript-eslint/eslint-plugin": "^7.16.1",
"@typescript-eslint/parser": "^7.16.1",
"@vercel/webpack-asset-relocator-loader": "1.7.3",
"classnames": "^2.5.1",
"cross-env": "^7.0.3",
"css-loader": "^7.1.2",
"electron": "^31.2.1",
"eslint": "^9.7.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-react": "^7.34.4",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"json-loader": "^0.5.7",
"node-loader": "^2.0.0",
"react-refresh": "^0.14.2",
"sass": "^1.77.8",
"sass-loader": "^14.2.1",
"style-loader": "^4.0.0",
"ts-loader": "9.5.1",
"typescript": "^5.5.3",
"webpack": "^5.93.0"
},
"dependencies": {
"@plastichub/fs": "^0.13.41",
"@plastichub/osr-commons": "^0.5.2",
"@rjsf/core": "^5.24.1",
"@rjsf/mui": "^5.24.1",
"@rjsf/utils": "^5.24.1",
"@rjsf/validator-ajv8": "^5.24.1",
"electron-squirrel-startup": "^1.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
import { app, BrowserWindow } from 'electron';
import { createAppWindow } from './appWindow';
/** Handle creating/removing shortcuts on Windows when installing/uninstalling. */
if (require('electron-squirrel-startup')) {
app.quit();
}
/**
* This method will be called when Electron has finished
* initialization and is ready to create browser windows.
* Some APIs can only be used after this event occurs.
*/
app.on('ready', createAppWindow);
/**
* Emitted when the application is activated. Various actions can
* trigger this event, such as launching the application for the first time,
* attempting to re-launch the application when it's already running,
* or clicking on the application's dock or taskbar icon.
*/
app.on('activate', () => {
/**
* On OS X 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 (BrowserWindow.getAllWindows().length === 0) {
createAppWindow();
}
});
/**
* Emitted when all windows have been closed.
*/
app.on('window-all-closed', () => {
/**
* On OS X it is common for applications and their menu bar
* to stay active until the user quits explicitly with Cmd + Q
*/
if (process.platform !== 'darwin') {
app.quit();
}
});
/**
* In this file you can include the rest of your app's specific main process code.
* You can also put them in separate files and import them here.
*/

View File

@ -0,0 +1,63 @@
import { app, BrowserWindow } from 'electron';
import path from 'path';
import { registerTitlebarIpc } from '@main/window/titlebarIpc';
// Electron Forge automatically creates these entry points
declare const APP_WINDOW_WEBPACK_ENTRY: string;
declare const APP_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
let appWindow: BrowserWindow;
/**
* Create Application Window
* @returns {BrowserWindow} Application Window Instance
*/
export function createAppWindow(): BrowserWindow {
// Create new window instance
appWindow = new BrowserWindow({
width: 800,
height: 600,
backgroundColor: '#202020',
show: false,
autoHideMenuBar: true,
frame: false,
titleBarStyle: 'hidden',
icon: path.resolve('assets/images/appIcon.ico'),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
nodeIntegrationInSubFrames: false,
preload: APP_WINDOW_PRELOAD_WEBPACK_ENTRY,
sandbox: false,
},
});
// Load the index.html of the app window.
appWindow.loadURL(APP_WINDOW_WEBPACK_ENTRY);
// Show window when its ready to
appWindow.on('ready-to-show', () => appWindow.show());
// Register Inter Process Communication for main process
registerMainIPC();
// Close all windows when main window is closed
appWindow.on('close', () => {
appWindow = null;
app.quit();
});
return appWindow;
}
/**
* Register Inter Process Communication
*/
function registerMainIPC() {
/**
* Here you can assign IPC related codes for the application window
* to Communicate asynchronously from the main process to renderer processes.
*/
registerTitlebarIpc(appWindow);
}

View File

@ -0,0 +1,16 @@
Copyright (c) 2021-2022 Guasam
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you
wrote the original software. If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented
as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@ -0,0 +1,74 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar IPC (Renderer Process)
*/
import { ipcRenderer } from 'electron';
const titlebarContext = {
exit() {
ipcRenderer.invoke('window-close');
},
undo() {
ipcRenderer.invoke('web-undo');
},
redo() {
ipcRenderer.invoke('web-redo');
},
cut() {
ipcRenderer.invoke('web-cut');
},
copy() {
ipcRenderer.invoke('web-copy');
},
paste() {
ipcRenderer.invoke('web-paste');
},
delete() {
ipcRenderer.invoke('web-delete');
},
select_all() {
ipcRenderer.invoke('web-select-all');
},
reload() {
ipcRenderer.invoke('web-reload');
},
force_reload() {
ipcRenderer.invoke('web-force-reload');
},
toggle_devtools() {
ipcRenderer.invoke('web-toggle-devtools');
},
actual_size() {
ipcRenderer.invoke('web-actual-size');
},
zoom_in() {
ipcRenderer.invoke('web-zoom-in');
},
zoom_out() {
ipcRenderer.invoke('web-zoom-out');
},
toggle_fullscreen() {
ipcRenderer.invoke('web-toggle-fullscreen');
},
minimize() {
ipcRenderer.invoke('window-minimize');
},
toggle_maximize() {
ipcRenderer.invoke('window-toggle-maximize');
},
open_url(url: string) {
ipcRenderer.invoke('open-url', url);
},
};
export type TitlebarContextApi = typeof titlebarContext;
export default titlebarContext;

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar Context API
*/
import { TitlebarContextApi } from './titlebarContext';
const context: TitlebarContextApi = (window as any).electron_window?.titlebar;
export default context;

View File

@ -0,0 +1,95 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar IPC (Main Process)
*/
import { BrowserWindow, ipcMain, shell } from 'electron';
export const registerTitlebarIpc = (mainWindow: BrowserWindow) => {
ipcMain.handle('window-minimize', () => {
mainWindow.minimize();
});
ipcMain.handle('window-maximize', () => {
mainWindow.maximize();
});
ipcMain.handle('window-toggle-maximize', () => {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize();
} else {
mainWindow.maximize();
}
});
ipcMain.handle('window-close', () => {
mainWindow.close();
});
ipcMain.handle('web-undo', () => {
mainWindow.webContents.undo();
});
ipcMain.handle('web-redo', () => {
mainWindow.webContents.redo();
});
ipcMain.handle('web-cut', () => {
mainWindow.webContents.cut();
});
ipcMain.handle('web-copy', () => {
mainWindow.webContents.copy();
});
ipcMain.handle('web-paste', () => {
mainWindow.webContents.paste();
});
ipcMain.handle('web-delete', () => {
mainWindow.webContents.delete();
});
ipcMain.handle('web-select-all', () => {
mainWindow.webContents.selectAll();
});
ipcMain.handle('web-reload', () => {
mainWindow.webContents.reload();
});
ipcMain.handle('web-force-reload', () => {
mainWindow.webContents.reloadIgnoringCache();
});
ipcMain.handle('web-toggle-devtools', () => {
mainWindow.webContents.toggleDevTools();
});
ipcMain.handle('web-actual-size', () => {
mainWindow.webContents.setZoomLevel(0);
});
ipcMain.handle('web-zoom-in', () => {
mainWindow.webContents.setZoomLevel(mainWindow.webContents.zoomLevel + 0.5);
});
ipcMain.handle('web-zoom-out', () => {
mainWindow.webContents.setZoomLevel(mainWindow.webContents.zoomLevel - 0.5);
});
ipcMain.handle('web-toggle-fullscreen', () => {
mainWindow.setFullScreen(!mainWindow.fullScreen);
});
ipcMain.handle('open-url', (e, url) => {
shell.openExternal(url);
});
};

View File

@ -0,0 +1,160 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar Menu Items
*/
export type TitlebarMenuItem = {
name: string;
action?: string;
shortcut?: string;
value?: string | number;
items?: TitlebarMenuItem[];
};
export type TitlebarMenu = {
name: string;
items: TitlebarMenuItem[];
};
const titlebarMenus: TitlebarMenu[] = [
{
name: 'File',
items: [
{
name: 'Exit',
action: 'exit',
},
],
},
{
name: 'Edit',
items: [
{
name: 'Undo',
action: 'undo',
shortcut: 'Ctrl+Z',
},
{
name: 'Redo',
action: 'redo',
shortcut: 'Ctrl+Y',
},
{
name: '__',
},
{
name: 'Cut',
action: 'cut',
shortcut: 'Ctrl+X',
},
{
name: 'Copy',
action: 'copy',
shortcut: 'Ctrl+C',
},
{
name: 'Paste',
action: 'paste',
shortcut: 'Ctrl+V',
},
{
name: 'Delete',
action: 'delete',
},
{
name: '__',
},
{
name: 'Select All',
action: 'select_all',
shortcut: 'Ctrl+A',
},
],
},
{
name: 'View',
items: [
{
name: 'Reload',
action: 'reload',
shortcut: 'Ctrl+R',
},
{
name: 'Force Reload',
action: 'force_reload',
shortcut: 'Ctrl+Shift+R',
},
{
name: 'Toogle Developer Tools',
action: 'toggle_devtools',
shortcut: 'Ctrl+Shift+I',
},
{
name: '__',
},
{
name: 'Actual Size',
action: 'actual_size',
shortcut: 'Ctrl+0',
},
{
name: 'Zoom In',
action: 'zoom_in',
shortcut: 'Ctrl++',
},
{
name: 'Zoom Out',
action: 'zoom_out',
shortcut: 'Ctrl+-',
},
{
name: '__',
},
{
name: 'Toggle Fullscreen',
action: 'toggle_fullscreen',
shortcut: 'F11',
},
],
},
{
name: 'Window',
items: [
{
name: 'Maximize',
action: 'toggle_maximize',
shortcut: 'Toggle'
},
{
name: 'Minimize',
action: 'minimize',
shortcut: 'Ctrl+M',
},
{
name: 'Close',
action: 'exit',
shortcut: 'Ctrl+W',
},
],
},
{
name: 'Credits',
items: [
{
name: 'Guasam',
action: 'open_url',
value: 'https://github.com/guasam',
shortcut: '@guasam',
},
],
},
];
export default titlebarMenus;

View File

@ -0,0 +1,6 @@
import { contextBridge } from 'electron';
import titlebarContext from './titlebarContext';
contextBridge.exposeInMainWorld('electron_window', {
titlebar: titlebarContext,
});

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>ERWT Boilerplate</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -0,0 +1,35 @@
import '@main/window/windowPreload';
// Say something
console.log('[ERWT] : Preload execution started');
// Get versions
window.addEventListener('DOMContentLoaded', () => {
const app = document.getElementById('app');
const { env } = process;
const versions: Record<string, unknown> = {};
// ERWT Package version
versions['erwt'] = env['npm_package_version'];
versions['license'] = env['npm_package_license'];
// Process versions
for (const type of ['chrome', 'node', 'electron']) {
versions[type] = process.versions[type].replace('+', '');
}
// NPM deps versions
for (const type of ['react']) {
const v = env['npm_package_dependencies_' + type];
if (v) versions[type] = v.replace('^', '');
}
// NPM @dev deps versions
for (const type of ['webpack', 'typescript']) {
const v = env['npm_package_devDependencies_' + type];
if (v) versions[type] = v.replace('^', '');
}
// Set versions to app data
app.setAttribute('data-versions', JSON.stringify(versions));
});

View File

@ -0,0 +1,17 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
import WindowFrame from '@renderer/window/WindowFrame';
import Application from '@components/Application';
// Say something
console.log('[ERWT] : Renderer execution started');
// Application to Render
const app = (
<WindowFrame title='ERWT Boilerplate' platform='windows'>
<Application />
</WindowFrame>
);
// Render application in DOM
createRoot(document.getElementById('app')).render(app);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
import chrome from '@assets/icons/chrome.png';
import react from '@assets/icons/react.png';
import typescript from '@assets/icons/typescript.png';
import erwt from '@assets/icons/erwt.png';
import electron from '@assets/icons/electron.png';
import nodejs from '@assets/icons/nodejs.png';
import webpack from '@assets/icons/webpack.png';
import license from '@assets/icons/license.png';
export default {
chrome,
react,
typescript,
erwt,
electron,
nodejs,
webpack,
license,
};

View File

@ -0,0 +1,358 @@
/**
* Licensed under the MIT License. See LICENSE file in the project root for license information.
* Copyright (c) 2022 Codesbiome, guasam
*
* @author : guasam
* @project : ERWT Boilerplate
* @package : Application Sass Stylesheet
*/
@import './dark_theme.scss';
@import './light_theme.scss';
/**
*==========================================================================
* Application Specific Stylesheet
*==========================================================================
*
* Here we use the codes to apply application specific style
*/
::selection {
background: var(--selection-bgcolor);
color: var(--selection-color);
}
::-webkit-scrollbar {
width: var(--scroll-width);
&-track {
background: var(--scroll-track-bgcolor);
}
&-thumb {
background: var(--scroll-thumb-bgcolor);
}
&-thumb:hover {
background: var(--scroll-thumb-hover-bgcolor);
}
}
html,
body,
#app {
height: 100%;
}
body {
margin: 0;
font-size: var(--app-font-size);
font-family: var(--app-font-family);
color: var(--app-color);
background: var(--app-bgcolor);
line-height: 1.5;
}
/* Grid texture */
body {
background-size: 32px 32px;
background-image:
linear-gradient(to right, #7070700d 1px, transparent 1px),
linear-gradient(to bottom, #7070700d 1px, transparent 1px);
}
h1 {
margin: 0;
}
#app {
display: flex;
flex-direction: column;
box-sizing: border-box;
user-select: none;
&.has-border {
border: var(--app-border-color);
}
}
button {
background: var(--button-bgcolor);
color: var(--button-color);
font-weight: normal;
text-shadow: 0px 1px var(--button-shadow-color);
font-family: var(--app-font-family);
border: var(--button-border);
padding: 0.5rem 1rem;
border-radius: 6px;
font-size: 0.875rem;
cursor: pointer;
display: inline-flex;
justify-content: space-around;
align-items: center;
outline: none;
min-width: 140px;
&:hover {
background: var(--button-hover-bgcolor);
}
&:active {
background: var(--button-active-bgcolor);
}
&>span {
color: var(--button-badge-color);
background-color: var(--button-badge-bgcolor);
font-size: 12px;
width: 24px;
height: 24px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
display: none;
}
img {
width: 22px;
opacity: 0.8;
}
}
.rotate {
animation: rotate 4.5s linear infinite;
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
.main-heading {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 2rem;
img {
margin-right: 1rem;
}
h1 {
font-size: 1.5rem;
font-weight: 400;
color: var(--erwt-heading-color);
line-height: 1;
text-transform: uppercase;
}
}
.hidden {
display: none !important;
}
.center {
text-align: center;
}
.main-teaser {
position: relative;
display: flex;
line-height: 25px;
font-size: 14px;
color: #d8d8d894;
width: 60%;
margin: 0 auto;
margin-bottom: 3rem;
justify-content: center;
padding: 1rem;
padding-right: 1rem;
border-radius: 0 0 8px 8px;
box-shadow: 0 8px 10px 0px rgba(0, 0, 0, 0.01);
}
.main-teaser:after {
content: "";
position: absolute;
top: 0;
width: calc(100% + 40px);
height: 1px;
background: var(--app-accent-color);
left: -20px;
box-shadow: 0 10px 20px 1px rgb(0 0 0 / 85%);
border-radius: 8px;
}
.versions {
display: flex;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
border-radius: 10px;
box-shadow: 0 0 20px inset rgb(0 0 0 / 3%);
width: 80%;
margin: 0 auto;
}
.versions .item {
background: #0000003b;
color: #d1d1d1;
width: calc(50% - 1rem);
padding: 6px 12px;
display: flex;
justify-content: space-between;
font-size: 14px;
margin: 0;
box-sizing: border-box;
border-radius: 4px;
&>* {
display: flex;
}
&-icon {
width: 20px;
height: 20px;
margin-right: 10px;
opacity: 0.8;
}
&>span {
color: gray;
text-align: right;
}
}
#erwt {
// user-select: none;
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
background: var(--erwt-gradient);
.header {
padding: 4rem 2rem 0rem 2rem;
max-width: 700px;
margin: 0 auto;
}
.footer {
padding: 2rem;
background: var(--app-footer-bgColor);
padding-bottom: 3rem;
}
}
/**
*==========================================================================
* Titlebar Overrides for different themes
*==========================================================================
*/
.window-titlebar {
background: var(--titlebar-bgcolor);
height: auto;
overflow: hidden;
&-icon {
min-height: 33px;
img {
border-radius: 50%;
}
}
.window-title {
color: var(--titlebar-title-color);
}
.menu-item {
&.active .menu-title {
background: var(--titlebar-menu-title-active-bgcolor);
box-shadow: var(--titlebar-menu-title-shadow);
color: var(--titlebar-color);
border-color: var(--titlebar-menu-title-active-border-color);
border-radius: 4px 4px 0 0;
border-top-color: var(--app-accent-color);
}
}
.menu-title {
font-weight: normal;
text-shadow: none;
color: var(--titlebar-color);
border-color: transparent;
border-width: 1px 1px 0 1px;
border-style: solid;
padding: 2px 8px;
margin-right: 2px;
border-radius: 4px;
&:hover {
background-color: var(--titlebar-menu-title-hover-bgcolor);
}
}
.menu-popup {
display: none;
position: fixed;
background-color: var(--titlebar-popup-bgcolor);
min-width: 70px;
border: var(--titlebar-popup-border);
border-top: 0;
padding: 0.25rem 0;
box-shadow: 4px 10px 10px #0000002e;
z-index: 10000;
border-radius: 0 6px 6px 6px;
&-item {
padding: 0.3125rem 1rem;
&:hover {
background: var(--titlebar-popup-item-hover-bgcolor);
.popup-item-shortcut {
color: var(--titlebar-popup-item-hover-shortcut-color);
}
.popup-item-name {
color: var(--titlebar-popup-item-hover-color);
}
}
}
}
.popup-item-separator {
background: var(--titlebar-menu-separator-bgcolor);
}
.popup-item-name {
padding-right: 2rem;
color: var(--titlebar-popup-item-name-color);
text-shadow: 0px 1px var(--titlebar-popup-item-name-shadow-color);
}
.popup-item-shortcut {
color: var(--titlebar-popup-item-shortcut-color);
text-shadow: none;
letter-spacing: 0.5px;
}
&-controls.type-windows .control {
color: var(--titlebar-color);
font-family: Arial, Helvetica, sans-serif;
&:hover {
color: var(--titlebar-color);
background: var(--titlebar-popup-item-hover-bgcolor);
}
&.close:hover {
color: #fff;
}
}
}

View File

@ -0,0 +1,57 @@
/*
*=========================================================================
* ERWT Dark Theme
*=========================================================================
*
* Here we define the Dark Theme (stylesheet) for application.
*/
:root {
// Application
--app-accent-color: #27954f;
--app-font-size: 16px;
--app-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--app-bgcolor: #1d1d1d;
--app-border-color: #3b3f44;
// Scrollbar
--scroll-width: 10px;
--scroll-track-bgcolor: #2f2f2f52;
--scroll-thumb-bgcolor: rgba(59, 59, 59, 0.747);
--scroll-thumb-hover-bgcolor: #555;
// Selection
--selection-bgcolor: var(--app-accent-color);
--selection-color: #fff;
// Button
--button-color: #fff;
--button-border: 1px solid #222424;
--button-bgcolor: hsl(0, 0%, 22%);
--button-hover-bgcolor: hsl(0, 0%, 24%);
--button-active-bgcolor: hsl(0deg 0% 20%);
--button-shadow-color: #00000078;
// Titlebar
--titlebar-bgcolor: #252525;
--titlebar-color: hsl(0, 0%, 85%);
--titlebar-title-color: hsl(0, 0%, 85%);
--titlebar-menu-border-color: #2d2c2c;
--titlebar-menu-title-hover-bgcolor: hsl(0deg 0% 12%);
--titlebar-menu-title-active-bgcolor: #1e1e1e;
--titlebar-menu-title-active-border-color: var(--titlebar-menu-border-color);
--titlebar-menu-separator-bgcolor: var(--titlebar-menu-border-color);
--titlebar-popup-bgcolor: #1e1e1e;
--titlebar-popup-border: 1px solid var(--titlebar-menu-border-color);
--titlebar-popup-shadow: 4px 10px 10px rgba(0, 0, 0, 0.2);
--titlebar-popup-item-name-color: hsl(0, 0%, 75%);
--titlebar-popup-item-shortcut-color: hsla(0, 0%, 55%, 0.8);
--titlebar-popup-item-hover-color: hsl(0, 0%, 85%);
--titlebar-popup-item-hover-bgcolor: hsl(0 0% 16.22%);
--titlebar-popup-item-hover-shortcut-color: var(--app-accent-color);
--titlebar-popup-item-name-shadow-color: #151515;
// ERWT
--erwt-heading-color: #ddddddec;
}

View File

@ -0,0 +1,67 @@
/*
*=========================================================================
* ERWT Light Theme
*=========================================================================
*
* Light theme for ERWT application.
*/
body:not(.dark-mode) {
// Application
--app-accent-color: #27954f;
--app-bgcolor: #e2e2e2;
// Selection
--selection-bgcolor: var(--app-accent-color);
--selection-color: #fff;
// Scrollbar
--scroll-track-bgcolor: #2f2f2f1f;
--scroll-thumb-bgcolor: rgb(59 59 59 / 30%);
--scroll-thumb-hover-bgcolor: var(--app-accent-color);
// Button
--button-border: 1px solid #eaeaea;
--button-bgcolor: #fff;
--button-color: #424242;
--button-shadow-color: white;
--button-hover-bgcolor: hsl(0, 0%, 98%);
--button-active-bgcolor: hsl(0, 0%, 96%);
// Titlebar
--titlebar-bgcolor: #d5d5d5c4;
--titlebar-color: #1f1f1f;
--titlebar-title-color: var(--titlebar-color);
--titlebar-menu-title-hover-bgcolor: #e6e6e69e;
--titlebar-popup-bgcolor: hsl(0deg 0% 99%);
--titlebar-menu-title-active-bgcolor: hsl(0deg 0% 99%);
--titlebar-menu-title-active-border-color: #d3d6d8;
--titlebar-popup-border: 1px solid #d3d6d8;
--titlebar-menu-separator-bgcolor: #d3d6d8;
--titlebar-popup-item-name-color: #0e0e0e;
--titlebar-popup-item-name-shadow-color: rgba(255, 255, 255, 0.8);
--titlebar-popup-item-hover-color: #000000;
--titlebar-popup-item-hover-shortcut-color: var(--app-accent-color);
--titlebar-popup-item-hover-bgcolor: #d6dadea2;
// ERWT
--erwt-heading-color: #282828;
// Overrides
.main-teaser {
color: #2e2e2e;
&:after {
box-shadow: none;
}
}
.versions .item {
color: #656565;
background: #ffffff5e;
&>span {
color: #999999;
}
}
}

View File

@ -0,0 +1,33 @@
import classNames from 'classnames';
import React from 'react';
interface IControlButtonProps {
readonly name: string;
readonly path: string;
readonly title: string;
}
const ControlButton: React.FC<
IControlButtonProps & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
const { name, path, title, ...rest } = props;
const { onClick } = rest;
const className = classNames('control', name);
return (
<div
aria-label={name}
className={className}
onClick={onClick}
title={title}
{...rest}
>
<svg aria-hidden='true' version='1.1' width='10' height='10'>
<path fill='currentColor' d={path} />
</svg>
</div>
);
};
export default ControlButton;

View File

@ -0,0 +1,16 @@
Copyright (c) 2021-2022 Guasam
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you
wrote the original software. If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented
as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@ -0,0 +1,196 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Titlebar (Component)
*/
import React, { createRef, useContext, useEffect, useRef, useState } from 'react';
import titlebarMenus from '@main/window/titlebarMenus';
import classNames from 'classnames';
import WindowControls from './WindowControls';
import context from '@main/window/titlebarContextApi';
import { WindowContext } from './WindowFrame';
import './titlebar.scss';
type Props = {
title: string;
mode: 'centered-title';
icon?: string;
};
const Titlebar: React.FC<Props> = (props) => {
const activeMenuIndex = useRef<number | null>(null);
const menusRef = titlebarMenus.map(() => createRef<HTMLDivElement>());
const [menusVisible, setMenusVisible] = useState(true);
const windowContext = useContext(WindowContext);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.repeat) return; // Prevent repeatation of toggle when key holding
if (e.altKey) {
// Hiding menus? close active menu popup
if (menusVisible) {
closeActiveMenu();
}
setMenusVisible(!menusVisible);
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [menusVisible, menusRef]);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (activeMenuIndex.current != null) {
if (
menusRef[activeMenuIndex.current].current &&
!menusRef[activeMenuIndex.current].current?.contains(event.target as Node)
) {
// console.log('You clicked outside of me!');
closeActiveMenu();
}
}
}
if (activeMenuIndex != null) {
document.addEventListener('mousedown', handleClickOutside);
// console.log('added event');
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
// console.log('remove event');
};
}, [activeMenuIndex, menusRef]);
function showMenu(index: number, e: React.MouseEvent<HTMLDivElement>) {
e.stopPropagation();
e.preventDefault();
if (menusRef[index].current?.classList.contains('active')) {
// close..
closeActiveMenu();
} else {
// open..
menusRef[index].current?.classList.add('active');
activeMenuIndex.current = index;
menusRef[index].current?.parentElement?.classList.add('active');
}
}
function onMenuHover(index: number) {
if (activeMenuIndex.current != null) {
menusRef[activeMenuIndex.current].current?.classList.toggle('active');
menusRef[index].current?.classList.toggle('active');
menusRef[index].current?.parentElement?.classList.toggle('active');
menusRef[activeMenuIndex.current].current?.parentElement?.classList.toggle(
'active',
);
activeMenuIndex.current = index;
}
}
function closeActiveMenu() {
if (activeMenuIndex.current != null) {
menusRef[activeMenuIndex.current].current?.classList.remove('active');
menusRef[activeMenuIndex.current]?.current?.parentElement?.classList.remove('active');
activeMenuIndex.current = null;
}
}
function handleAction(action?: string, value?: string | number) {
closeActiveMenu();
const c: Record<string, CallableFunction> = context;
if (action) {
if (typeof c[action] === 'function') {
c[action](value);
} else {
console.log(`action [${action}] is not available in titlebar context`);
}
}
}
return (
<div className='window-titlebar'>
{props.icon ? (
<section className='window-titlebar-icon'>
<img src={props.icon} alt='titlebar icon' />
</section>
) : (
''
)}
<section
className={classNames('window-titlebar-content', {
centered: props.mode === 'centered-title',
})}
>
{menusVisible ? '' : <div className='window-title'>{props.title}</div>}
</section>
<section
className={classNames('window-titlebar-menu', {
hidden: !menusVisible,
})}
>
{titlebarMenus.map((item, menuIndex) => {
return (
<div className='menu-item' key={`menu_${menuIndex}`}>
<div
className='menu-title'
onClick={(e) => showMenu(menuIndex, e)}
onMouseEnter={() => onMenuHover(menuIndex)}
onMouseDown={(e) => e.preventDefault()}
>
{item.name}
</div>
<div className='menu-popup' ref={menusRef[menuIndex]}>
{item.items?.map((menuItem, menuItemIndex) => {
if (menuItem.name === '__') {
return (
<div
key={`menu_${menuIndex}_popup_item_${menuItemIndex}`}
className='popup-item-separator'
></div>
);
}
return (
<div
key={`menu_${menuIndex}_popup_item_${menuItemIndex}`}
className='menu-popup-item'
onClick={() =>
handleAction(menuItem.action, menuItem.value)
}
onMouseDown={(e) => e.preventDefault()}
>
<div className='popup-item-name'>{menuItem.name}</div>
<div className='popup-item-shortcut'>
{menuItem.shortcut}
</div>
</div>
);
})}
</div>
</div>
);
})}
</section>
<WindowControls platform={windowContext.platform} tooltips={true} />
</div>
);
};
export default Titlebar;

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Controls - Close, Minimize, Maximize (Component)
*/
import classNames from 'classnames';
import React from 'react';
import context from '@main/window/titlebarContextApi';
import ControlButton from './ControlButton';
type Props = {
platform: string;
tooltips?: boolean;
};
const closePath =
'M 0,0 0,0.7 4.3,5 0,9.3 0,10 0.7,10 5,5.7 9.3,10 10,10 10,9.3 5.7,5 10,0.7 10,0 9.3,0 5,4.3 0.7,0 Z';
const maximizePath = 'M 0,0 0,10 10,10 10,0 Z M 1,1 9,1 9,9 1,9 Z';
const minimizePath = 'M 0,5 10,5 10,6 0,6 Z';
const WindowControls: React.FC<Props> = (props) => {
return (
<section
className={classNames(
'window-titlebar-controls',
`type-${props.platform}`,
)}
>
<ControlButton
name='minimize'
onClick={() => context.minimize()}
path={minimizePath}
title={props.tooltips ? 'Minimize' : null}
/>
<ControlButton
name='maximize'
onClick={() => context.toggle_maximize()}
path={maximizePath}
title={props.tooltips ? 'Maximize' : null}
/>
<ControlButton
name='close'
onClick={() => context.exit()}
path={closePath}
title={props.tooltips ? 'Close' : null}
/>
</section>
);
};
export default WindowControls;

View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Frame (Component)
*/
import React, { useEffect, useRef } from 'react';
import Titlebar from './Titlebar';
import logo from '@assets/images/logo.png';
type Props = {
title?: string;
borderColor?: string;
platform: 'windows' | 'mac';
children: React.ReactNode;
};
type Context = {
platform: 'windows' | 'mac';
};
export const WindowContext = React.createContext<Context>({
platform: 'windows',
});
const WindowFrame: React.FC<Props> = (props) => {
const itsRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const { parentElement } = itsRef.current;
parentElement.classList.add('has-electron-window');
parentElement.classList.add('has-border');
// Apply border color if prop given
if (props.borderColor) {
parentElement.style.borderColor = props.borderColor;
}
}, []);
return (
<WindowContext.Provider value={{ platform: props.platform }}>
{/* Reference creator */}
<div className='start-electron-window' ref={itsRef}></div>
{/* Window Titlebar */}
<Titlebar
title={props.title ?? 'Electron Window'}
mode='centered-title'
icon={logo}
/>
{/* Window Content (Application to render) */}
<div className='window-content'>{props.children}</div>
</WindowContext.Provider>
);
};
export default WindowFrame;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,211 @@
$titlebar-baseSize: 16px;
$titlebar-height: 28px;
$titlebar-bg: #171b21;
$titlebar-iconSize: 16px;
$em: $titlebar-baseSize*1em;
/*
|--------------------------------------------------------------------------
| Window Titlebar
|--------------------------------------------------------------------------
*/
.window-titlebar {
display: flex;
align-items: stretch;
font-size: $titlebar-baseSize;
height: $titlebar-height;
background: $titlebar-bg;
-webkit-app-region: drag;
user-select: none;
position: relative;
&>section {
display: flex;
align-items: center;
}
&-content {
flex: 1;
font-size: calc($titlebar-baseSize - 3px);
color: #a9b0bb;
&.centered {
width: 100%;
height: 100%;
position: absolute;
justify-content: center;
}
}
&-icon {
padding: 0 0.75em;
img {
width: $titlebar-iconSize;
height: $titlebar-iconSize;
}
}
.popup-item {
&-name {
padding-right: 2rem;
color: #d8d8d8;
}
&-shortcut {
color: #73757c;
text-shadow: none;
}
&-separator {
height: 1px;
background: #3c4043;
margin: 4px 0;
}
}
}
/*
|--------------------------------------------------------------------------
| Titlebar Menu
|--------------------------------------------------------------------------
*/
.window-titlebar .menu {
flex: 1;
&-item {
position: relative;
}
&-item.active {
.menu-title {
background: #3c4043;
color: #bfbfbf;
}
}
&-title {
padding: 4px 10px;
font-size: 0.8125rem;
text-shadow: 0px 1px 1px black;
-webkit-app-region: no-drag;
color: #97a0b1;
&:hover {
background-color: #1f252c;
}
}
&-popup {
display: none;
position: fixed;
background: #292a2d;
min-width: 70px;
border: 1px solid #3c4043;
padding: 0.25rem 0;
box-shadow: 2px 1px 4px hsla(0, 0%, 0%, 0.5);
z-index: 10000;
&.active {
display: block;
}
&-item {
display: flex;
justify-content: space-between;
font-size: 0.8125rem;
text-shadow: 0px 1px 1px black;
padding: 0.375rem 1rem;
&:hover {
background: #1761cb;
.popup-item-shortcut {
color: #8cbbff;
}
}
}
}
}
/*
|--------------------------------------------------------------------------
| Titlebar Controls (Max, Min, Close)
|--------------------------------------------------------------------------
*/
.window-titlebar-controls {
display: flex;
align-items: stretch;
position: absolute;
right: 0;
top: 0;
bottom: 0;
color: #969799;
&.type-windows {
.control {
padding: 0 1.15em;
font-size: 0.875em;
display: flex;
height: 100%;
align-items: center;
-webkit-app-region: no-drag;
&.close:hover {
background: #e10000;
}
&:hover {
background: #242d38;
color: #d8d9db;
}
}
}
&.type-mac {
.control {
width: 16px;
height: 16px;
background: #0e0e0e99;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.675rem;
color: transparent;
-webkit-app-region: no-drag;
opacity: 0.8;
&:hover {
opacity: 1;
}
}
.control.close {
background: #f46d60;
}
.control.maximize {
background: #59ca56;
}
.control.minimize {
background: #f9c04e;
}
}
}
/*
|--------------------------------------------------------------------------
| Window Content
|--------------------------------------------------------------------------
*/
.window-content {
position: relative;
overflow: auto;
flex: 1;
}

View File

@ -0,0 +1,4 @@
declare module '*.css';
declare module '*.png';
declare module '*.jpg';
declare module '*.jpeg';

View File

@ -0,0 +1,88 @@
// Forge Configuration
const path = require('path');
const rootDir = process.cwd();
module.exports = {
// Packager Config
packagerConfig: {
// Create asar archive for main, renderer process files
asar: true,
// Set executable name
executableName: 'ERWT',
// Set application copyright
appCopyright: '© 2021-2024 Codesbiome, Guasam',
// Set application icon
icon: path.resolve('assets/images/appIcon.ico'),
},
// Forge Makers
makers: [
{
// Squirrel.Windows is a no-prompt, no-hassle, no-admin method of installing
// Windows applications and is therefore the most user friendly you can get.
name: '@electron-forge/maker-squirrel',
config: {
name: 'electron-react-typescript-webpack-2022',
},
},
{
// The Zip target builds basic .zip files containing your packaged application.
// There are no platform specific dependencies for using this maker and it will run on any platform.
name: '@electron-forge/maker-zip',
platforms: ['darwin'],
},
{
// The deb target builds .deb packages, which are the standard package format for Debian-based
// Linux distributions such as Ubuntu.
name: '@electron-forge/maker-deb',
config: {},
},
{
// The RPM target builds .rpm files, which is the standard package format for
// RedHat-based Linux distributions such as Fedora.
name: '@electron-forge/maker-rpm',
config: {},
},
],
// Forge Plugins
plugins: [
{
name: '@electron-forge/plugin-webpack',
config: {
// Fix content-security-policy error when image or video src isn't same origin
// Remove 'unsafe-eval' to get rid of console warning in development mode.
devContentSecurityPolicy: `default-src 'self' 'unsafe-inline' data:; script-src 'self' 'unsafe-inline' data:`,
// Webpack Dev Server port
port: 3000,
// Logger port
loggerPort: 9000,
// Main process webpack configuration
mainConfig: path.join(rootDir, 'tools/webpack/webpack.main.js'),
// Renderer process webpack configuration
renderer: {
// Configuration file path
config: path.join(rootDir, 'tools/webpack/webpack.renderer.js'),
// Entrypoints of the application
entryPoints: [
{
// Window process name
name: 'app_window',
// React Hot Module Replacement (HMR)
rhmr: 'react-hot-loader/patch',
// HTML index file template
html: path.join(rootDir, 'src/renderer/app.html'),
// App Renderer
js: path.join(rootDir, 'src/renderer/appRenderer.tsx'),
// App Preload
preload: {
js: path.join(rootDir, 'src/renderer/appPreload.tsx'),
},
},
],
},
devServer: {
liveReload: false,
},
},
},
],
};

View File

@ -0,0 +1,12 @@
const { createWebpackAliases } = require('./webpack.helpers');
// Export aliases
module.exports = createWebpackAliases({
'@assets': 'assets',
'@components': 'src/renderer/components',
'@common': 'src/common',
'@main': 'src/main',
'@renderer': 'src/renderer',
'@src': 'src',
'@styles': 'src/renderer/styles',
});

View File

@ -0,0 +1,20 @@
const path = require('path');
const cwd = process.cwd();
function inDev() {
return process.env.NODE_ENV == 'development';
}
function createWebpackAliases (aliases) {
const result = {};
for (const name in aliases) {
result[name] = path.join(cwd, aliases[name]);
}
return result;
}
module.exports = {
inDev,
createWebpackAliases,
};

View File

@ -0,0 +1,16 @@
module.exports = {
/**
* This is the main entry point for your application, it's the first file
* that runs in the main process.
*/
entry: ['./src/main/app.ts'],
// Put your normal webpack config below here
module: {
rules: require('./webpack.rules'),
},
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css', '.json'],
alias: require('./webpack.aliases'),
},
stats: 'minimal',
};

View File

@ -0,0 +1,10 @@
const webpack = require('webpack');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const { inDev } = require('./webpack.helpers');
module.exports = [
new ForkTsCheckerWebpackPlugin(),
inDev() && new webpack.HotModuleReplacementPlugin(),
inDev() && new ReactRefreshWebpackPlugin(),
].filter(Boolean);

View File

@ -0,0 +1,22 @@
const rules = require('./webpack.rules');
const plugins = require('./webpack.plugins');
module.exports = {
module: {
rules,
},
plugins: plugins,
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.css'],
alias: {
// Custom Aliases
...require('./webpack.aliases'),
},
},
stats: 'minimal',
/**
* Fix: Enable inline-source-map to fix following:
* Dev tools: unable to load source maps over custom protocol
*/
devtool: 'inline-source-map',
};

View File

@ -0,0 +1,51 @@
module.exports = [
{
// Add support for native node modules
test: /native_modules\/.+\.node$/,
use: 'node-loader',
},
{
test: /\.(m?js|node)$/,
parser: { amd: false },
use: {
loader: '@vercel/webpack-asset-relocator-loader',
options: {
outputAssetBase: 'native_modules',
},
},
},
{
// Typescript loader
test: /\.tsx?$/,
exclude: /(node_modules|\.webpack)/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
},
{
// CSS Loader
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
},
{
// SCSS (SASS) Loader
test: /\.s[ac]ss$/i,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},
{
// Assets loader
// More information here https://webpack.js.org/guides/asset-modules/
test: /\.(gif|jpe?g|tiff|png|webp|bmp|svg|eot|ttf|woff|woff2)$/i,
type: 'asset',
generator: {
filename: 'assets/[hash][ext][query]',
},
},
];

View File

@ -0,0 +1,28 @@
{
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"target": "ES6",
"module": "ESNext",
"skipLibCheck": true,
"esModuleInterop": true,
"noImplicitAny": true,
"sourceMap": true,
"baseUrl": ".",
"outDir": "dist",
"moduleResolution": "node",
"resolveJsonModule": true,
"paths": {
"*": ["node_modules/*"],
"@assets/*": ["./assets/*"],
"@components/*": ["./src/renderer/components/*"],
"@common/*": ["./src/common/*"],
"@main/*": ["./src/main/*"],
"@renderer/*": ["./src/renderer/*"],
"@src/*": ["./src/*"],
"@misc/*": ["./misc/*"],
"@styles/*": ["./src/renderer/styles/*"]
}
},
"include": ["src/**/*", "tools/**/*"]
}