├── .editorconfig
├── .eslintrc.cjs
├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── eslint.config.js
├── index.html
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── icon-256.ico
├── icon.icns
├── icon.ico
└── icon.png
├── screenshot.png
├── server.cjs
├── src
├── App.vue
├── assets
│ ├── base.css
│ ├── logo.svg
│ ├── main.css
│ └── nw.png
├── components
│ ├── ExternalLink.vue
│ └── ResourceGroup.vue
├── helpers
│ ├── applyPrototypes.js
│ └── constants.js
├── main.js
├── router
│ └── index.js
├── stores
│ └── counter.js
└── views
│ ├── FsExample.vue
│ ├── HelloWorld.vue
│ ├── PiniaDemo.vue
│ └── ResourceLinks.vue
├── tests
└── unit
│ ├── App.test.js
│ ├── __snapshots__
│ └── App.test.js.snap
│ ├── components
│ └── ExternalLink.test.js
│ ├── main.test.js
│ ├── setup.js
│ ├── testHelpers.js
│ └── views
│ ├── FsExample.test.js
│ ├── HelloWorld.test.js
│ ├── PiniaDemo.test.js
│ └── __snapshots__
│ ├── FsExample.test.js.snap
│ ├── HelloWorld.test.js.snap
│ └── PiniaDemo.test.js.snap
├── vite.config.js
└── waitOnConfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # Top-most EditorConfig file
4 | root = true
5 |
6 | # defaults for all files
7 | [*]
8 | charset = utf-8
9 | end_of_line = lf
10 | indent_size = 2
11 | indent_style = space
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 |
15 | # Markdown files uses two trailing spaces to indicate a
16 | [*.{md,snap}]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | // Due to a bug in the ESLint import plugin, this file is required
2 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ "main" ]
9 | pull_request:
10 | branches: [ "main" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | - uses: volta-cli/action@v4
20 | - run: node -v
21 | - run: npm -v
22 | - run: npm ci
23 | - run: npm run build:vue
24 | - run: npm run lint
25 | - run: npm t
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-vue
14 | dist-ssr
15 | coverage
16 | *.local
17 |
18 | # Editor directories and files
19 | .vscode/*
20 | !.vscode/extensions.json
21 | .idea
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw?
27 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # "No Ideologies" Code of Conduct
2 |
3 | The following are the guidelines we expect our community members and maintainers to follow.
4 |
5 | * * *
6 |
7 | ## Terminology and Scope
8 |
9 | **What defines a "maintainer"?**
10 |
11 | * A maintainer is anyone that interacts with the community on behalf of this project. Amount of code written is not a qualifier. A maintainer may include those who solely help in support roles such as in resolving issues, improving documentation, administrating or moderating forums/chatrooms, or any other non-coding specific roles. Maintainers also include those that are responsible for the building and upkeep of the project.
12 |
13 | **What defines a "community member"?**
14 |
15 | * Anyone interacting with this project directly, including maintainers.
16 |
17 | **What is the scope of these guidelines?**
18 |
19 | * These guidelines apply only to this project and forms of communication directly related to it, such as issue trackers, forums, chatrooms, and in person events specific to this project. If a member is violating these guidelines outside of this project or on other platforms, that is beyond our scope and any grievances should be handled on those platforms.
20 |
21 | **Discussing the guidelines:**
22 |
23 | * Discussions around these guidelines, improving, updating, or altering them, is permitted so long as the discussions do not violate any existing guidelines.
24 |
25 | * * *
26 |
27 | ## Guidelines
28 |
29 | ### Guidelines for community members
30 |
31 | This project is technical in nature and not based around any particular non-technical ideology. As such, communication that is based primarily around ideologies unrelated to the technologies used by this repository are not permitted.
32 |
33 | Any discussion or communication that is primarily focused around an ideology, be it about race, gender, politics, religion, or anything else non-technical, is not allowed. Everyone has their own ideological preferences, beliefs, and opinions. We do not seek to marginalize, exclude, or judge anyone for their ideologies. To prevent conflict between those with differing or opposing ideologies, all communication on these subjects are prohibited. Some discussions around these topics may be important, however this project is not the proper channel for these discussions.
34 |
35 | ### Guidelines for maintainers
36 |
37 | * Maintainers must abide by the same rules as all other community members mentioned above. However, in addition, maintainers are held to a higher standard, explained below.
38 | * Maintainers should answer all questions politely.
39 | * If someone is upset or angry about something, it's probably because it's difficult to use, so thank them for bringing it to your attention and address ways to solve the problem. Maintainers should focus on the content of the message, and not on how it was delivered.
40 | * A maintainer should seek to update members when an issue they brought up is resolved.
41 |
42 | * * *
43 |
44 | ## Appropriate response to violations
45 |
46 | How to respond to a community member or maintainer violating a guideline.
47 |
48 | 1. If an issue is created that violates a guideline a maintainer should close and lock the issue, explaining "This issue is in violation of our code of conduct. Please review it before posting again." with a link to this document.
49 | 1. If a member repeatedly violates the guidelines established in this document, they should be politely warned that continuing to violate the rules may result in being banned from the community. This means revoking access and support to interactions relating directly to the project (issue trackers, chatrooms, forums, in person events, etc.). However, they may continue to use the technology in accordance with its license.
50 | 1. If a maintainer is in violation of a guideline, they should be informed of such with a link to this document. If additional actions are required of the maintainer but not taken, then other maintainers should be informed of these inactions.
51 | 1. If a maintainer repeatedly violates the guidelines established in this document, they should be politely warned that continuing to violate the rules may result in being banned from the community. This means revoking access and support to interactions relating directly to the project (issue trackers, chatrooms, forums, in person events, etc.). However, they may continue to use the technology in accordance with its license. In addition, future contributions to this project may be ignored as well.
52 |
53 | * * *
54 |
55 | Based on version 1.0.3 from https://github.com/CodifiedConduct/coc-no-ideologies
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 The Jared Wilcurt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NW.js + Vue 3 Desktop App Boilerplate
2 |
3 | The easiest, quickest, and best option for building Desktop Apps with Vue.
4 |
5 | 100% test coverage. Vue-DevTools built in.
6 |
7 | All you do is `npm install && npm start` and you got a desktop app and web app development environment with Vue-DevTools built-in.
8 |
9 | **Does this work for web or just desktop?**
10 |
11 | **Both.** This repo will build both for web and desktop and includes a simple `this.isDesktop` flag so you can add desktop specific features that won't show on the web. This repo has 100% test coverage including tests for both web and desktop builds. You could even theoretically add NativeScript-Vue into the mix and build for native mobile as well (though that is not set up in this repo).
12 |
13 | Run `npm run build` and you're ready to ship/deploy: Web App, Windows Installer, OSX and Linux apps.
14 |
15 | 
16 |
17 |
18 | ## Technology colophon
19 |
20 | * **Vue 3** - Frontend framework
21 | * **NW.js** - Desktop App runtime environment
22 | * Chromium 137
23 | * Node.js 23.11.0
24 | * **Vue-DevTools** - Official Vite plugin
25 | * **Vite** - Dev Server/Bundler/App build tool
26 | * **Pinia** - Global State Management
27 | * **Vue-Router** - Frontend routing/navigation
28 | * **Options API** - [Component organizational structure](https://user-images.githubusercontent.com/4629794/204181213-6c9bcece-62fb-4790-8fc2-7df546ca7df5.png)
29 | * **Constants Plugin** - Gives you a [dedicated place to store constants](https://github.com/TheJaredWilcurt/vue-options-api-constants-plugin) in a component
30 | * **NW-Builder-Phoenix** - Automated desktop builds
31 | * **ESLint** - Code error prevention and stylistic consistency
32 | * Vue Linting
33 | * Accessibility Linting
34 | * Test Linting
35 | * Import Linting
36 | * **Vitest** - Vite-based Unit/integration/behavioral testing
37 | * 100% test coverage examples
38 | * @vue/test-utils - Test helpers for interacting with Vue in tests
39 | * vue3-snapshot-serializer - Dramatically improved snapshot formatting
40 | * @pinia/testing - Initialize Pinia in tests
41 |
42 |
43 | ## Documentation
44 |
45 | In all `.vue` components, you have access to `nw`, `global`, `process`, `require`, and the boolean `isDesktop`:
46 |
47 | ```js
48 | methods: {
49 | example: function () {
50 | if (this.isDesktop) {
51 | console.log('Your OS is ' + this.process.platform);
52 | console.log('Your AppData location is ' + this.nw.App.dataPath);
53 | // Sets a value on Node's global, meaning other windows have access to this data.
54 | this.global.cow = 'moo';
55 | // The contents of the current directory
56 | console.log(this.require('fs').readdirSync('.'));
57 | }
58 | }
59 | }
60 | ```
61 |
62 | Or even directly from the template (with some slight changes to work within the Vue context):
63 | ```html
64 |
65 | Your OS is {{ process.platform }}.
66 | Your AppData location is {{ nw.App.dataPath }}.
67 |
71 | The contents of the current directory are {{ nw.require('fs').readdirSync('.') }}.
72 |
73 | ```
74 |
75 |
76 | ## Running locally
77 |
78 | 1. Download, Fork, or Clone this repo
79 | 1. Install [Volta](https://volta.sh)
80 | * It will handle using the correct Node version based on the `package.json`
81 | 1. Run `npm install`
82 | 1. Run `npm start`
83 |
84 |
85 | ## Lint
86 |
87 | Uses rules in `./eslint.json`
88 |
89 | 1. `npm run lint` to see linting errors
90 | 1. `npm run fix` to auto-fix linting errors (where possible)
91 |
92 |
93 | ## Tests
94 |
95 | 1. `npm t` runs all unit tests and shows coverage output
96 | 1. `npm t -- -u` runs all unit tests, updating snapshots (use with care)
97 |
98 |
99 | ## Building for distribution
100 |
101 | 1. `npm run build:clean` will delete your `./dist` and `./dist-vue` folders
102 | 1. `npm run build:vue` will build just your Vue app for web distribution (`./dist-vue`)
103 | 1. `npm run build:nw` will build just your NW.js app (`./dist`) for all supported platforms (Windows, OSX, Linux 32-Bit, Linux 64-Bit)
104 | 1. `npm run build` is your all-in-one command. It will clean out the old dist folders and build your Vue and NW.js app
105 |
106 |
107 | ## IMPORTANT NOTE ABOUT BUILDS
108 |
109 | They take a long time. If you do `npm run build` expect it to take 10-30 minutes. This can be adjusted by changing the build params in the `package.json`. The more platforms and build types, the longer it takes. You can also remove the `--concurrent` from the `build:nw` script to see a status of what has been completed. This will allow individual pieces to finish faster, but the entire build will take longer.
110 |
111 |
112 | ## Removing Pinia
113 |
114 | I set up Pinia in this project to save you time (and because it's amazing). If you don't need global state management for your project, you can remove Pinia by doing the following:
115 |
116 | * Delete the `/src/store` folder and its contents
117 | * Delete `/src/views/PiniaDemo.vue`
118 | * Delete `/tests/unit/views/PiniaDemo.test.js`
119 | * Remove the Pinia Demo `RouterLink` from `/src/App.vue`
120 | * Remove import and route object relating to "PiniaDemo" from `/src/router/index.js`
121 | * Remove the lines of code from `/tests/unit/testHelpers.js` that say "pinia"
122 | * Remove the lines of code from `/package.json` that say "pinia"
123 | * `npm install && npm t -- -u`
124 | * `git add -A && git commit -m "Removed Pinia"`
125 |
126 |
127 | ## Alternatives
128 |
129 | * [Vue 3 Desktop and Mobile](https://github.com/rigor789/nw-vue3-boilerplate) - Fork of this repo but with NativeScript added to also build for Android and iOS.
130 | * [nw-vue-cli-example](https://github.com/nwutils/nw-vue-cli-example) - Uses Vue-CLI (WebPack), has Vue 2 and Vue 3 branches.
131 | * [nwjs-vue](https://github.com/elegantweb/nwjs-vue) - Uses Vue-CLI 2
132 | * [vue-desktop-basic](https://github.com/TheJaredWilcurt/vue-desktop-basic) - Does not use a build system at all, all `.vue` files run directly in the browser context
133 | * [nw-vue3-typescript-pinia](https://github.com/codeh2o/nw-vue3-typescript-pinia) - Old fork of this repo but with TS added
134 |
135 |
136 | ## Updating to newer NW.js versions
137 |
138 | 1. When updating the version of NW.js devDependency, also update these:
139 | * `package.json` version, devDeps, build nwVersion, volta
140 | * `build.target` in `vite.config.js`
141 | * Update the Chromium/Node version numbers at the top of the README
142 | 1. Bump the version number, and all the npm scripts that reference the version number
143 | 1. Run `npm run regression` after updating dependencies or other major changes to verify builds still work correctly
144 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import path from 'node:path';
2 |
3 | import pluginJs from '@eslint/js';
4 | import tjwBase from 'eslint-config-tjw-base';
5 | import tjwImport from 'eslint-config-tjw-import';
6 | import tjwJest from 'eslint-config-tjw-jest';
7 | import tjwVue from 'eslint-config-tjw-vue';
8 | import pluginImport from 'eslint-plugin-import';
9 | import pluginJest from 'eslint-plugin-jest';
10 | import pluginVue from 'eslint-plugin-vue';
11 | import pluginVueA11y from 'eslint-plugin-vuejs-accessibility';
12 |
13 | const __dirname = import.meta.dirname;
14 | const vue3Recommended = pluginVue.configs['flat/recommended'];
15 | const vueA11yRecommended = pluginVueA11y.configs['flat/recommended'];
16 |
17 | export default [
18 | pluginJs.configs.recommended,
19 | pluginImport.flatConfigs.recommended,
20 | pluginJest.configs['flat/recommended'],
21 | ...vue3Recommended,
22 | ...vueA11yRecommended,
23 | tjwBase.configs.recommended,
24 | tjwImport,
25 | tjwJest.configs.recommended,
26 | tjwVue,
27 | {
28 | // project specific rules/settings
29 | languageOptions: {
30 | globals: {
31 | vi: true
32 | }
33 | },
34 | rules: {
35 | 'import/no-unused-modules': 'off',
36 | 'import/no-extraneous-dependencies': 'off',
37 |
38 | // If this is not turned off, linting throws because it can't find 'jest' install
39 | 'jest/no-deprecated-functions': 'off',
40 | 'vuejs-accessibility/label-has-for': [
41 | 'error',
42 | {
43 | components: ['Label'],
44 | required: {
45 | some: ['nesting', 'id']
46 | },
47 | allowChildren: false
48 | }
49 | ]
50 | },
51 | settings: {
52 | 'import/resolver': {
53 | vite: {
54 | viteConfig: {
55 | resolve: {
56 | alias: {
57 | '@': path.resolve(__dirname, 'src'),
58 | '@@': path.resolve(__dirname, 'tests'),
59 | '@@@': path.resolve(__dirname, 'docs')
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 | }
67 | ];
68 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Your App Name Here
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["./src/*"],
6 | "@@/*": ["./tests/*"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "ManifestComments": [
3 | "Only add dependencies that you want shipped to the end user, for everything else, use devDependencies, including things that will be bundled by Vite.",
4 | "NW.js requires a name and a main, everything else is optional.",
5 | "The build section is used by nwjs-builder-phoenix, see its documentation for more info",
6 | "To turn spell checking off, remove it from the chromium-args in this file",
7 | "Unit tests inaccurately report 1 line of code not being covered because this bug: vitejs/vite-plugin-vue #368"
8 | ],
9 | "name": "your-app-name",
10 | "version": "1.1.0",
11 | "main": "http://localhost:4175",
12 | "node-remote": "http://localhost:4175",
13 | "node-main": "",
14 | "window": {
15 | "width": 960,
16 | "height": 600,
17 | "min_width": 800,
18 | "min_height": 500,
19 | "icon": "public/icon.png"
20 | },
21 | "private": true,
22 | "scripts": {
23 | "postinstall": "npx --yes base-volta-off-of-nwjs@latest",
24 | "start": "concurrently -k npm:dev:web npm:dev:desktop",
25 | "dev:web": "vite --port 4175",
26 | "dev:desktop": "wait-on -c waitOnConfig.json http-get://localhost:4175 && nw .",
27 | "build": "npm run build:clean && npm run build:vue && npm run build:nw",
28 | "build:clean": "rimraf ./dist-vue ./dist",
29 | "build:vue": "vite build",
30 | "build:nw": "build --concurrent --tasks win-x86,linux-x86,linux-x64,mac-x64 --mirror https://dl.nwjs.io/ .",
31 | "build:win": "npm run build:win:clean && npm run build:vue && build --tasks win-x86 --mirror https://dl.nwjs.io/ .",
32 | "build:lin": "npm run build:lin:clean && npm run build:vue && build --tasks linux-x64 --mirror https://dl.nwjs.io/ .",
33 | "build:win:clean": "rimraf ./dist-vue ./dist/your-app-name-1.1.0-win-x86 ./dist/your-app-name-1.1.0-win-x86.zip ./dist/your-app-name-1.1.0-win-x86.7z ./dist/your-app-name-1.1.0-win-x86-Setup.exe",
34 | "build:lin:clean": "rimraf ./dist-vue ./dist/your-app-name-1.1.0-linux-x64 ./dist/your-app-name-1.1.0-linux-x64.zip",
35 | "run:win": "dist\\your-app-name-1.1.0-win-x86\\your-app-name.exe",
36 | "run:lin": "./dist/your-app-name-1.1.0-linux-x64/your-app-name",
37 | "regression": "rd /s /q node_modules & rd /s /q node_modules & rd /s /q node_modules & npm install && npm run lint && npm test && npm run build:win && npm run run:win",
38 | "regression:lin": "rm -r -f node_modules && npm install && npm run lint && npm test && npm run build:lin && npm run run:lin",
39 | "lint": "eslint --ext .js,.vue src tests",
40 | "fix": "npm run lint -- --fix",
41 | "test": "vitest run --coverage"
42 | },
43 | "dependencies": {
44 | "express": "^5.1.0"
45 | },
46 | "devDependencies": {
47 | "@eslint/js": "^9.27.0",
48 | "@pinia/testing": "^1.0.1",
49 | "@stylistic/eslint-plugin": "^4.4.0",
50 | "@vitejs/plugin-vue": "^5.2.4",
51 | "@vitest/coverage-v8": "^3.1.4",
52 | "@vue/test-utils": "^2.4.6",
53 | "concurrently": "^9.1.0",
54 | "eslint": "^9.27.0",
55 | "eslint-config-tjw-base": "^4.2.0",
56 | "eslint-config-tjw-import": "^2.0.0",
57 | "eslint-config-tjw-jest": "^3.0.0",
58 | "eslint-config-tjw-vue": "^4.0.0",
59 | "eslint-import-resolver-vite": "^2.1.0",
60 | "eslint-plugin-import": "^2.31.0",
61 | "eslint-plugin-jest": "^28.11.0",
62 | "eslint-plugin-vue": "^10.1.0",
63 | "eslint-plugin-vuejs-accessibility": "^2.4.1",
64 | "globals": "^16.2.0",
65 | "happy-dom": "^17.4.7",
66 | "nw": "0.100.0-sdk",
67 | "nwjs-builder-phoenix": "^1.15.0",
68 | "pinia": "^3.0.2",
69 | "rimraf": "^6.0.1",
70 | "vite": "^6.3.5",
71 | "vite-plugin-vue-devtools": "^7.7.6",
72 | "vitest": "^3.1.4",
73 | "vue": "^3.5.15",
74 | "vue-options-api-constants-plugin": "^1.0.3",
75 | "vue-router": "^4.5.1",
76 | "vue3-snapshot-serializer": "^2.10.0",
77 | "wait-on": "^8.0.3"
78 | },
79 | "chromium-args": "--enable-spell-checking --disable-features=ProcessPerSiteUpToMainFrameThreshold",
80 | "build": {
81 | "nwVersion": "v0.100.0",
82 | "nwFlavor": "normal",
83 | "targets": [
84 | "zip",
85 | "nsis7z"
86 | ],
87 | "files": [
88 | "**/*"
89 | ],
90 | "excludes": [
91 | "src/**/*",
92 | "tests/**/*",
93 | "public/**/*",
94 | "dist-vue/**/*.js.map",
95 | "dist-vue/**/*.css.map",
96 | "dist-vue/**/*-legacy*",
97 | ".editorconfig",
98 | ".eslintignore",
99 | ".eslintrc",
100 | ".gitignore",
101 | "CODE_OF_CONDUCT.md",
102 | "index.html",
103 | "jsconfig.json",
104 | "package-lock.json",
105 | "screenshot.png",
106 | "vite.config.js",
107 | "waitOnConfig.json"
108 | ],
109 | "strippedProperties": [
110 | "ManifestComments",
111 | "scripts",
112 | "devDependencies",
113 | "build",
114 | "volta"
115 | ],
116 | "overriddenProperties": {
117 | "main": "http://localhost:4185",
118 | "node-remote": "http://localhost:4185",
119 | "node-main": "server.cjs",
120 | "chromium-args": "--enable-spell-checking",
121 | "window": {
122 | "width": 960,
123 | "height": 600,
124 | "min_width": 700,
125 | "min_height": 500,
126 | "icon": "dist-vue/icon.png"
127 | }
128 | },
129 | "win": {
130 | "icon": "public/icon-256.ico"
131 | },
132 | "mac": {
133 | "icon": "public/icon.icns"
134 | },
135 | "nsis": {
136 | "icon": "public/icon-256.ico",
137 | "unIcon": "public/icon.ico",
138 | "languages": [
139 | "English"
140 | ],
141 | "diffUpdaters": false,
142 | "hashCalculation": true
143 | }
144 | },
145 | "type": "module",
146 | "volta": {
147 | "node": "23.11.0"
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/public/favicon.ico
--------------------------------------------------------------------------------
/public/icon-256.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/public/icon-256.ico
--------------------------------------------------------------------------------
/public/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/public/icon.icns
--------------------------------------------------------------------------------
/public/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/public/icon.ico
--------------------------------------------------------------------------------
/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/public/icon.png
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/screenshot.png
--------------------------------------------------------------------------------
/server.cjs:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 |
3 | const app = express();
4 | app.use(express.static('./dist-vue'));
5 | app.listen(4185);
6 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
56 |
--------------------------------------------------------------------------------
/src/assets/base.css:
--------------------------------------------------------------------------------
1 | /* color palette from https://github.com/vuejs/theme */
2 | :root {
3 | --vt-c-white: #FFFFFF;
4 | --vt-c-black: #181818;
5 | --vt-c-text-light-1: var(--vt-c-indigo);
6 | --vt-c-text-dark-1: var(--vt-c-white);
7 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
8 | }
9 |
10 | /* semantic color variables for this project */
11 | :root {
12 | --color-background: var(--vt-c-white);
13 | --color-heading: var(--vt-c-text-light-1);
14 | --color-text: var(--vt-c-text-light-1);
15 | --section-gap: 160px;
16 | }
17 |
18 | @media (prefers-color-scheme: dark) {
19 | :root {
20 | --color-background: var(--vt-c-black);
21 | --color-heading: var(--vt-c-text-dark-1);
22 | --color-text: var(--vt-c-text-dark-2);
23 | }
24 | }
25 |
26 | *,
27 | *::before,
28 | *::after {
29 | position: relative;
30 | margin: 0;
31 | font-weight: normal;
32 | box-sizing: border-box;
33 | }
34 |
35 | body {
36 | min-height: 100vh;
37 | background: var(--color-background);
38 | color: var(--color-text);
39 | font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
40 | font-size: 15px;
41 | line-height: 1.6;
42 | text-rendering: optimizeLegibility;
43 | -webkit-font-smoothing: antialiased;
44 | -moz-osx-font-smoothing: grayscale;
45 | transition: color 0.5s, background-color 0.5s;
46 | }
47 |
--------------------------------------------------------------------------------
/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/assets/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
3 | #app {
4 | max-width: 1280px;
5 | margin: 0px auto;
6 | padding: 2rem;
7 | font-weight: normal;
8 | }
9 |
10 | a,
11 | .green {
12 | color: hsla(160, 100%, 37%, 1);
13 | text-decoration: none;
14 | transition: 0.4s;
15 | }
16 |
17 | button {
18 | background: hsla(160, 100%, 37%, 1);
19 | border: 0px;
20 | border-radius: 3px;
21 | padding: 4px 6px;
22 | }
23 | button:hover {
24 | background: hsla(160, 100%, 40%, 1);
25 | }
26 | button:active {
27 | background: hsla(160, 100%, 43%, 1);
28 | }
29 |
30 | strong {
31 | font-weight: bold;
32 | }
33 |
34 | hr {
35 | width: 100%;
36 | background: var(--color-text);
37 | margin: 15px 0px;
38 | }
39 |
40 | textarea {
41 | width: 100%;
42 | min-height: 15rem;
43 | background: #333;
44 | border: 0px;
45 | margin-top: 1rem;
46 | padding: 0.5rem;
47 | color: #CCC;
48 | }
49 |
50 | .flex {
51 | display: flex;
52 | }
53 | .container {
54 | display: inline-block;
55 | min-width: 200px;
56 | margin-right: 2rem;
57 | vertical-align: top;
58 | }
59 |
60 | .mt-1 {
61 | margin-top: 1rem;
62 | }
63 |
64 | .mb-2 {
65 | margin-bottom: 2rem;
66 | }
67 |
68 | .center {
69 | text-align: center;
70 | }
71 |
72 | @media (hover: hover) {
73 | a:hover {
74 | background-color: hsla(160, 100%, 37%, 0.2);
75 | }
76 | }
77 |
78 | @media (min-width: 1024px) {
79 | body {
80 | display: flex;
81 | flex-direction: row;
82 | justify-content: center;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/assets/nw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nwutils/nw-vue3-boilerplate/5ddc8fc4bad195c23ab6d047e92d54616473263c/src/assets/nw.png
--------------------------------------------------------------------------------
/src/components/ExternalLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
35 |
--------------------------------------------------------------------------------
/src/components/ResourceGroup.vue:
--------------------------------------------------------------------------------
1 |
2 |
126 | Notice that the
127 |
128 | same app conditionally renders
129 |
130 | different content in a normal browser than
131 |
132 | when ran as a desktop app
133 |
134 | .
135 |
121 | Notice that the
122 |
123 | same app conditionally renders
124 |
125 | different content in a normal browser than
126 |
127 | when ran as a desktop app
128 |
129 | .
130 |