Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c34f10bb2 | ||
|
|
684f3330e9 | ||
|
|
178bb0c012 | ||
|
|
39cc30de53 | ||
|
|
aae4223294 | ||
|
|
bddfa60f19 | ||
|
|
58b10cfcfe | ||
|
|
36a751bb7b | ||
|
|
6a67f07a9e | ||
|
|
c43871950c | ||
|
|
fe70701de8 | ||
|
|
80f5735d04 | ||
|
|
3305900cb8 | ||
|
|
c495e71f35 | ||
|
|
4721c46d8c | ||
|
|
0aaddf24c6 | ||
|
|
427fde27ad | ||
|
|
a12ba017bc | ||
|
|
7a2161d746 | ||
|
|
d0e7a319d6 | ||
|
|
4afafa5038 | ||
|
|
583680d311 | ||
|
|
70dd38f79d | ||
|
|
9120d05efc | ||
|
|
3a820b458f | ||
|
|
47f3b7fc89 | ||
|
|
838a3c78dd | ||
|
|
8d51cd5029 | ||
|
|
bfb9af05b0 | ||
|
|
897df3a5d4 | ||
|
|
d1296d1708 |
6
.env.example
Normal file
6
.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# githubs api has a rate limit of 60/h if not authorised.
|
||||
# you may quickly hit that and get rate limited. To counteract this, you can provide a github token
|
||||
# here and it will be used. To do so, create a token at the following links and just leave
|
||||
# all permissions at the defaults (public repos read only, 0 permissions):
|
||||
# https://github.com/settings/personal-access-tokens/new
|
||||
GITHUB_TOKEN=
|
||||
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -26,17 +26,3 @@ jobs:
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE: true
|
||||
|
||||
- name: Update AUR package
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
sudo apt install makepkg
|
||||
|
||||
echo $SSH_KEY > ~/.ssh/aur
|
||||
echo $SSH_PUB_KEY > ~/.ssh/aur.pub
|
||||
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur"
|
||||
|
||||
./scripts/aur_bump.sh
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
|
||||
SSH_PUB_KEY: ${{ secrets.AUR_SSH_PUB_KEY }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
dist
|
||||
node_modules
|
||||
.env
|
||||
|
||||
12
README.md
12
README.md
@@ -1,8 +1,16 @@
|
||||
# Vencord Desktop
|
||||
|
||||
A standalone Electron app that loads Discord & Vencord
|
||||
Vencord Desktop is a cross platform desktop app aiming to give you a snappier Discord experience with Vencord pre-installed
|
||||
|
||||
Vencord Desktop is currently in very early alpha. Bug reports, feature requests & contributions are highly appreciated!!
|
||||
Vencord Desktop is currently in beta
|
||||
|
||||
**Not yet supported**:
|
||||
- Screensharing
|
||||
- Global Keybinds
|
||||
|
||||
Bug reports, feature requests & contributions are highly appreciated!!
|
||||
|
||||

|
||||
|
||||
## Installing
|
||||
|
||||
|
||||
35
package.json
35
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "VencordDesktop",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.1",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
@@ -10,22 +10,26 @@
|
||||
"main": "dist/js/main.js",
|
||||
"scripts": {
|
||||
"build": "tsx scripts/build/build.mts",
|
||||
"build:dev": "pnpm build --dev",
|
||||
"package": "pnpm build && electron-builder",
|
||||
"package:dir": "pnpm build && electron-builder --dir",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.mts,.mjs",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"start": "pnpm build && electron .",
|
||||
"start:dev": "pnpm build --dev && electron .",
|
||||
"start:watch": "tsx scripts/startWatch.mts",
|
||||
"start:dev": "pnpm build:dev && electron .",
|
||||
"start:watch": "pnpm build:dev && tsx scripts/startWatch.mts",
|
||||
"test": "pnpm lint && pnpm testTypes",
|
||||
"testTypes": "tsc --noEmit",
|
||||
"watch": "pnpm build --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/react": "^18.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||
"@typescript-eslint/parser": "^5.57.1",
|
||||
"@vencord/types": "^0.1.2",
|
||||
"dotenv": "^16.0.3",
|
||||
"electron": "^23.2.0",
|
||||
"electron-builder": "^23.6.0",
|
||||
"esbuild": "^0.17.14",
|
||||
@@ -76,12 +80,33 @@
|
||||
}
|
||||
},
|
||||
"mac": {
|
||||
"target": [
|
||||
{
|
||||
"target": "default",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": "Network"
|
||||
},
|
||||
"nsis": {
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"include": "build/installer.nsh",
|
||||
"oneClick": false
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"portable"
|
||||
]
|
||||
},
|
||||
"publish": {
|
||||
"provider": "github",
|
||||
"releaseType": "release"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"arrpc": "^3.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
91
pnpm-lock.yaml
generated
91
pnpm-lock.yaml
generated
@@ -1,6 +1,14 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
dependencies:
|
||||
arrpc:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
|
||||
devDependencies:
|
||||
'@fal-works/esbuild-plugin-global-externals':
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2
|
||||
'@types/node':
|
||||
specifier: ^18.15.11
|
||||
version: 18.15.11
|
||||
@@ -13,6 +21,12 @@ devDependencies:
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^5.57.1
|
||||
version: 5.57.1(eslint@8.38.0)(typescript@5.0.2)
|
||||
'@vencord/types':
|
||||
specifier: ^0.1.2
|
||||
version: 0.1.2
|
||||
dotenv:
|
||||
specifier: ^16.0.3
|
||||
version: 16.0.3
|
||||
electron:
|
||||
specifier: ^23.2.0
|
||||
version: 23.2.0
|
||||
@@ -364,6 +378,10 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/@fal-works/esbuild-plugin-global-externals@2.1.2:
|
||||
resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
|
||||
dev: true
|
||||
|
||||
/@humanwhocodes/config-array@0.11.8:
|
||||
resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
@@ -489,6 +507,10 @@ packages:
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/lodash@4.14.194:
|
||||
resolution: {integrity: sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==}
|
||||
dev: true
|
||||
|
||||
/@types/minimatch@5.1.2:
|
||||
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
|
||||
dev: true
|
||||
@@ -519,6 +541,19 @@ packages:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: true
|
||||
|
||||
/@types/react-dom@18.0.11:
|
||||
resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.33
|
||||
dev: true
|
||||
|
||||
/@types/react@17.0.2:
|
||||
resolution: {integrity: sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.5
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@types/react@18.0.33:
|
||||
resolution: {integrity: sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==}
|
||||
dependencies:
|
||||
@@ -695,6 +730,18 @@ packages:
|
||||
eslint-visitor-keys: 3.4.0
|
||||
dev: true
|
||||
|
||||
/@vencord/types@0.1.2:
|
||||
resolution: {integrity: sha512-C/dqZHn3aod/4izZT9sgZEef4478M7QNKTY8Gx2yB1CRYawJcs6hupXT/1SMmepKqrULbltL04Cnh5ieBm3Ucw==}
|
||||
dependencies:
|
||||
'@types/lodash': 4.14.194
|
||||
'@types/node': 18.15.11
|
||||
'@types/react': 18.0.33
|
||||
'@types/react-dom': 18.0.11
|
||||
discord-types: 1.3.26
|
||||
standalone-electron-types: 1.0.0
|
||||
type-fest: 3.8.0
|
||||
dev: true
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.8.2):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
@@ -847,6 +894,15 @@ packages:
|
||||
es-shim-unscopables: 1.0.0
|
||||
dev: true
|
||||
|
||||
/arrpc@3.1.0:
|
||||
resolution: {integrity: sha512-QKagtB5fUDqDXT31tTUzcG3+rFxsMlrjKb3iE68/b2NbT1c6+0WYkkrJh4GaVPqH0Tlqy13sEgPW3XJ/VNmBDQ==}
|
||||
dependencies:
|
||||
ws: 8.13.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
/asar@3.2.0:
|
||||
resolution: {integrity: sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
@@ -1339,6 +1395,13 @@ packages:
|
||||
path-type: 4.0.0
|
||||
dev: true
|
||||
|
||||
/discord-types@1.3.26:
|
||||
resolution: {integrity: sha512-ToG51AOCH+JTQf7b+8vuYQe5Iqwz7nZ7StpECAZ/VZcI1ZhQk13pvt9KkRTfRv1xNvwJ2qib4e3+RifQlo8VPQ==}
|
||||
dependencies:
|
||||
'@types/react': 17.0.2
|
||||
moment: 2.29.4
|
||||
dev: true
|
||||
|
||||
/dmg-builder@23.6.0:
|
||||
resolution: {integrity: sha512-jFZvY1JohyHarIAlTbfQOk+HnceGjjAdFjVn3n8xlDWKsYNqbO4muca6qXEZTfGXeQMG7TYim6CeS5XKSfSsGA==}
|
||||
dependencies:
|
||||
@@ -1390,6 +1453,11 @@ packages:
|
||||
resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
|
||||
dev: true
|
||||
|
||||
/dotenv@16.0.3:
|
||||
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/dotenv@9.0.2:
|
||||
resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2867,6 +2935,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/moment@2.29.4:
|
||||
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
||||
dev: true
|
||||
|
||||
/ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
dev: true
|
||||
@@ -3382,6 +3454,12 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/standalone-electron-types@1.0.0:
|
||||
resolution: {integrity: sha512-0HOi/tlTz3mjWhsAz4uRbpQcHMZ+ifj1JzWW9nugykOHClBBG77ps8QinrzX1eow4Iw2pnC+RFaSYRgufF4BOg==}
|
||||
dependencies:
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/stat-mode@1.0.0:
|
||||
resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -3721,6 +3799,19 @@ packages:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
dev: true
|
||||
|
||||
/ws@8.13.0:
|
||||
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/xmlbuilder@15.1.1:
|
||||
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=$(git describe --tags --abbrev=0 | tr -d 'v')
|
||||
SHASUM=$(sha256sum "dist/VencordDesktop-$VERSION.tar.gz" | awk '{ print $1 }')
|
||||
|
||||
git clone ssh://aur@aur.archlinux.org/vencord-desktop-bin.git aurpkg
|
||||
|
||||
cd aurpkg
|
||||
|
||||
sed -i "s/^pkgver=.*$/pkgver=$VERSION/" PKGBUILD
|
||||
sed -i "s/^sha256sums=('.*'/sha256sums=('$SHASUM'/" PKGBUILD
|
||||
makepkg --printsrcinfo > .SRCINFO
|
||||
|
||||
git commit -a -m "Bump version to $VERSION"
|
||||
git push
|
||||
|
||||
cd ..
|
||||
rm -rf aurpkg
|
||||
@@ -1,5 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { BuildContext, BuildOptions, context } from "esbuild";
|
||||
|
||||
import vencordDep from "./vencordDep.mjs";
|
||||
|
||||
const isDev = process.argv.includes("--dev");
|
||||
|
||||
const CommonOpts: BuildOptions = {
|
||||
@@ -29,12 +37,20 @@ await Promise.all([
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/main/index.ts"],
|
||||
outfile: "dist/js/main.js"
|
||||
outfile: "dist/js/main.js",
|
||||
footer: { js: "//# sourceURL=VCDMain" }
|
||||
}),
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/preload/index.ts"],
|
||||
outfile: "dist/js/preload.js"
|
||||
outfile: "dist/js/preload.js",
|
||||
footer: { js: "//# sourceURL=VCDPreload" }
|
||||
}),
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/updater/preload.ts"],
|
||||
outfile: "dist/js/updaterPreload.js",
|
||||
footer: { js: "//# sourceURL=VCDUpdaterPreload" }
|
||||
}),
|
||||
createContext({
|
||||
...CommonOpts,
|
||||
@@ -46,7 +62,10 @@ await Promise.all([
|
||||
jsxFactory: "VencordCreateElement",
|
||||
jsxFragment: "VencordFragment",
|
||||
// Work around https://github.com/evanw/esbuild/issues/2460
|
||||
tsconfig: "./scripts/build/tsconfig.esbuild.json"
|
||||
tsconfig: "./scripts/build/tsconfig.esbuild.json",
|
||||
external: ["@vencord/types/*"],
|
||||
plugins: [vencordDep],
|
||||
footer: { js: "//# sourceURL=VCDRenderer" }
|
||||
})
|
||||
]);
|
||||
|
||||
@@ -55,8 +74,10 @@ const watch = process.argv.includes("--watch");
|
||||
if (watch) {
|
||||
await Promise.all(contexts.map(ctx => ctx.watch()));
|
||||
} else {
|
||||
await Promise.all(contexts.map(async ctx => {
|
||||
await ctx.rebuild();
|
||||
await ctx.dispose();
|
||||
}));
|
||||
await Promise.all(
|
||||
contexts.map(async ctx => {
|
||||
await ctx.rebuild();
|
||||
await ctx.dispose();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
export const VencordFragment = /* #__PURE__*/ Symbol.for("react.fragment");
|
||||
export let VencordCreateElement =
|
||||
(...args) => (VencordCreateElement = Vencord.Webpack.Common.React.createElement)(...args);
|
||||
export let VencordCreateElement = (...args) =>
|
||||
(VencordCreateElement = Vencord.Webpack.Common.React.createElement)(...args);
|
||||
|
||||
38
scripts/build/vencordDep.mts
Normal file
38
scripts/build/vencordDep.mts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { globalExternalsWithRegExp } from "@fal-works/esbuild-plugin-global-externals";
|
||||
|
||||
const names = {
|
||||
webpack: "Vencord.Webpack",
|
||||
"webpack/common": "Vencord.Webpack.Common",
|
||||
utils: "Vencord.Util",
|
||||
api: "Vencord.Api",
|
||||
"api/settings": "Vencord",
|
||||
components: "Vencord.Components"
|
||||
};
|
||||
|
||||
export default globalExternalsWithRegExp({
|
||||
getModuleInfo(modulePath) {
|
||||
const path = modulePath.replace("@vencord/types/", "");
|
||||
let varName = names[path];
|
||||
if (!varName) {
|
||||
const altMapping = names[path.split("/")[0]];
|
||||
if (!altMapping) throw new Error("Unknown module path: " + modulePath);
|
||||
|
||||
varName =
|
||||
altMapping +
|
||||
"." +
|
||||
// @ts-ignore
|
||||
path.split("/")[1].replaceAll("/", ".");
|
||||
}
|
||||
return {
|
||||
varName,
|
||||
type: "cjs"
|
||||
};
|
||||
},
|
||||
modulePathFilter: /^@vencord\/types.+$/
|
||||
});
|
||||
@@ -4,10 +4,8 @@
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
// FIXME: this is terrible
|
||||
import "./utils/dotenv";
|
||||
|
||||
const { Webpack, Plugins, Util } = Vencord;
|
||||
const { Common } = Webpack;
|
||||
const { plugins } = Plugins;
|
||||
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
|
||||
|
||||
export { Common, Plugins, plugins, Util, Webpack };
|
||||
spawnNodeModuleBin("electron", ["."]);
|
||||
@@ -1,15 +1,10 @@
|
||||
import { spawn as cpSpawn, SpawnOptions } from "child_process";
|
||||
import { join } from "path";
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
const EXT = process.platform === "win32" ? ".cmd" : "";
|
||||
import "./start";
|
||||
|
||||
const OPTS: SpawnOptions = {
|
||||
stdio: "inherit",
|
||||
};
|
||||
|
||||
function spawn(bin: string, args: string[]) {
|
||||
cpSpawn(join("node_modules", ".bin", bin + EXT), args, OPTS);
|
||||
}
|
||||
|
||||
spawn("tsx", ["scripts/build/build.mts", "--", "--watch", "--dev"]);
|
||||
spawn("electron", ["."]);
|
||||
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
|
||||
spawnNodeModuleBin("tsx", ["scripts/build/build.mts", "--", "--watch", "--dev"]);
|
||||
|
||||
9
scripts/utils/dotenv.ts
Normal file
9
scripts/utils/dotenv.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { config } from "dotenv";
|
||||
|
||||
config();
|
||||
18
scripts/utils/spawn.mts
Normal file
18
scripts/utils/spawn.mts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { spawn as spaaawn, SpawnOptions } from "child_process";
|
||||
import { join } from "path";
|
||||
|
||||
const EXT = process.platform === "win32" ? ".cmd" : "";
|
||||
|
||||
const OPTS: SpawnOptions = {
|
||||
stdio: "inherit"
|
||||
};
|
||||
|
||||
export function spawnNodeModuleBin(bin: string, args: string[]) {
|
||||
spaaawn(join("node_modules", ".bin", bin + EXT), args, OPTS);
|
||||
}
|
||||
2
src/globals.d.ts
vendored
2
src/globals.d.ts
vendored
@@ -7,8 +7,6 @@
|
||||
declare global {
|
||||
export var VencordDesktopNative: typeof import("preload/VencordDesktopNative").VencordDesktopNative;
|
||||
export var VencordDesktop: typeof import("renderer/index");
|
||||
// TODO
|
||||
export var Vencord: any;
|
||||
export var vcdLS: typeof localStorage;
|
||||
|
||||
export var IS_DEV: boolean;
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { ICON_PATH, STATIC_DIR } from "shared/paths";
|
||||
|
||||
@@ -19,7 +20,9 @@ export function createAboutWindow() {
|
||||
|
||||
makeLinksOpenExternally(about);
|
||||
|
||||
about.loadFile(join(STATIC_DIR, "about.html"));
|
||||
const html = readFileSync(join(STATIC_DIR, "about.html"), "utf-8").replaceAll("%VERSION%", app.getVersion());
|
||||
|
||||
about.loadURL("data:text/html;charset=utf-8," + html);
|
||||
|
||||
return about;
|
||||
}
|
||||
|
||||
21
src/main/arrpc.ts
Normal file
21
src/main/arrpc.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import Server from "arrpc";
|
||||
import { send as sendToBridge } from "arrpc/src/bridge";
|
||||
|
||||
import { Settings } from "./settings";
|
||||
|
||||
let server: any;
|
||||
|
||||
export async function initArRPC() {
|
||||
if (server || !Settings.store.arRPC) return;
|
||||
|
||||
server = await new Server();
|
||||
server.on("activity", sendToBridge);
|
||||
}
|
||||
|
||||
Settings.addChangeListener("arRPC", initArRPC);
|
||||
57
src/main/firstLaunch.ts
Normal file
57
src/main/firstLaunch.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
import { BrowserWindow } from "electron/main";
|
||||
import { copyFileSync, mkdirSync, readdirSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { STATIC_DIR } from "shared/paths";
|
||||
|
||||
import { DATA_DIR } from "./constants";
|
||||
import { createWindows } from "./mainWindow";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
export function createFirstLaunchTour() {
|
||||
const win = new BrowserWindow({
|
||||
...SplashProps,
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
height: 320,
|
||||
width: 550
|
||||
});
|
||||
|
||||
win.loadFile(join(STATIC_DIR, "first-launch.html"));
|
||||
win.webContents.addListener("console-message", (_e, _l, msg) => {
|
||||
if (msg === "cancel") return app.exit();
|
||||
|
||||
if (!msg.startsWith("form:")) return;
|
||||
const data = JSON.parse(msg.slice(5));
|
||||
|
||||
Settings.store.minimizeToTray = data.minimizeToTray;
|
||||
Settings.store.discordBranch = data.discordBranch;
|
||||
Settings.store.firstLaunch = false;
|
||||
|
||||
if (data.importSettings) {
|
||||
const from = join(app.getPath("userData"), "..", "Vencord", "settings");
|
||||
const to = join(DATA_DIR, "settings");
|
||||
try {
|
||||
const files = readdirSync(from);
|
||||
mkdirSync(to, { recursive: true });
|
||||
|
||||
for (const file of files) {
|
||||
copyFileSync(join(from, file), join(to, file));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to import settings:", e);
|
||||
}
|
||||
}
|
||||
|
||||
win.close();
|
||||
|
||||
createWindows();
|
||||
});
|
||||
}
|
||||
@@ -7,15 +7,14 @@
|
||||
import "./ipc";
|
||||
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { join } from "path";
|
||||
import { checkUpdates } from "updater/main";
|
||||
|
||||
import { ICON_PATH } from "../shared/paths";
|
||||
import { once } from "../shared/utils/once";
|
||||
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
|
||||
import { createMainWindow } from "./mainWindow";
|
||||
import { DATA_DIR } from "./constants";
|
||||
import { createFirstLaunchTour } from "./firstLaunch";
|
||||
import { createWindows, mainWin } from "./mainWindow";
|
||||
import { Settings } from "./settings";
|
||||
import { createSplashWindow } from "./splash";
|
||||
import { ensureVencordFiles } from "./utils/vencordLoader";
|
||||
|
||||
if (IS_DEV) {
|
||||
require("source-map-support").install();
|
||||
}
|
||||
@@ -23,16 +22,24 @@ if (IS_DEV) {
|
||||
// Make the Vencord files use our DATA_DIR
|
||||
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
|
||||
|
||||
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
|
||||
function init() {
|
||||
// <-- BEGIN COPY PASTED FROM DISCORD -->
|
||||
|
||||
let mainWin: BrowserWindow | null = null;
|
||||
// work around chrome 66 disabling autoplay by default
|
||||
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
|
||||
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
console.log("Vencord Desktop is already running. Quitting...");
|
||||
app.quit();
|
||||
} else {
|
||||
app.on("second-instance", () => {
|
||||
if (mainWin) {
|
||||
// WinRetrieveSuggestionsOnlyOnDemand: Work around electron 13 bug w/ async spellchecking on Windows.
|
||||
// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service.
|
||||
app.commandLine.appendSwitch(
|
||||
"disable-features",
|
||||
"WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService"
|
||||
);
|
||||
|
||||
// <-- END COPY PASTED FROM DISCORD -->
|
||||
|
||||
app.on("second-instance", (_event, _cmdLine, _cwd, data: any) => {
|
||||
if (data.IS_DEV) app.quit();
|
||||
else if (mainWin) {
|
||||
if (mainWin.isMinimized()) mainWin.restore();
|
||||
if (!mainWin.isVisible()) mainWin.show();
|
||||
mainWin.focus();
|
||||
@@ -40,10 +47,11 @@ if (!app.requestSingleInstanceLock()) {
|
||||
});
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
checkUpdates();
|
||||
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.desktop");
|
||||
else if (process.platform === "darwin") app.dock.setIcon(ICON_PATH);
|
||||
|
||||
createWindows();
|
||||
bootstrap();
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindows();
|
||||
@@ -51,22 +59,24 @@ if (!app.requestSingleInstanceLock()) {
|
||||
});
|
||||
}
|
||||
|
||||
async function createWindows() {
|
||||
const splash = createSplashWindow();
|
||||
if (!app.requestSingleInstanceLock({ IS_DEV })) {
|
||||
if (IS_DEV) {
|
||||
console.log("Vencord Desktop is already running. Quitting previous instance...");
|
||||
init();
|
||||
} else {
|
||||
console.log("Vencord Desktop is already running. Quitting...");
|
||||
app.quit();
|
||||
}
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
await ensureVencordFiles();
|
||||
runVencordMain();
|
||||
|
||||
mainWin = createMainWindow();
|
||||
|
||||
mainWin.once("ready-to-show", () => {
|
||||
splash.destroy();
|
||||
mainWin!.show();
|
||||
|
||||
if (Settings.store.maximized) {
|
||||
mainWin!.maximize();
|
||||
}
|
||||
});
|
||||
async function bootstrap() {
|
||||
if (!Object.hasOwn(Settings.store, "firstLaunch")) {
|
||||
createFirstLaunchTour();
|
||||
} else {
|
||||
createWindows();
|
||||
}
|
||||
}
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, dialog, ipcMain, shell } from "electron";
|
||||
import { app, dialog, ipcMain, session, shell } from "electron";
|
||||
import { existsSync, readFileSync, watch } from "fs";
|
||||
import { open, readFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
@@ -52,8 +52,20 @@ ipcMain.handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => {
|
||||
shell.showItemInFolder(path);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.FOCUS, () => {
|
||||
mainWin?.focus();
|
||||
ipcMain.handle(IpcEvents.FOCUS, e => {
|
||||
e.sender.focus();
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.CLOSE, e => {
|
||||
e.sender.close();
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
|
||||
const ses = session.defaultSession;
|
||||
|
||||
const available = ses.availableSpellCheckerLanguages;
|
||||
const applicable = languages.filter(l => available.includes(l)).slice(0, 3);
|
||||
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
|
||||
import { app, BrowserWindow, BrowserWindowConstructorOptions, Menu, Tray } from "electron";
|
||||
import { join } from "path";
|
||||
import { once } from "shared/utils/once";
|
||||
|
||||
import { ICON_PATH } from "../shared/paths";
|
||||
import { createAboutWindow } from "./about";
|
||||
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH } from "./constants";
|
||||
import { initArRPC } from "./arrpc";
|
||||
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH, VENCORD_FILES_DIR } from "./constants";
|
||||
import { Settings, VencordSettings } from "./settings";
|
||||
import { createSplashWindow } from "./splash";
|
||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||
import { downloadVencordFiles } from "./utils/vencordLoader";
|
||||
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";
|
||||
|
||||
let isQuitting = false;
|
||||
let tray: Tray;
|
||||
@@ -84,6 +87,7 @@ function initMenuBar(win: BrowserWindow) {
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: "Vencord Desktop",
|
||||
role: "appMenu",
|
||||
submenu: [
|
||||
{
|
||||
label: "About Vencord Desktop",
|
||||
@@ -98,28 +102,6 @@ function initMenuBar(win: BrowserWindow) {
|
||||
},
|
||||
toolTip: "Vencord Desktop will automatically restart after this operation"
|
||||
},
|
||||
{
|
||||
label: "Toggle Developer Tools",
|
||||
accelerator: "CmdOrCtrl+Shift+I",
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Toggle Developer Tools (Hidden)",
|
||||
accelerator: "F12",
|
||||
visible: false,
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Reload Window",
|
||||
accelerator: "CmdOrCtrl+R",
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Relaunch",
|
||||
accelerator: "CmdOrCtrl+Shift+R",
|
||||
@@ -132,6 +114,7 @@ function initMenuBar(win: BrowserWindow) {
|
||||
label: "Quit",
|
||||
accelerator: wantCtrlQ ? "CmdOrCtrl+Q" : void 0,
|
||||
visible: !isWindows,
|
||||
role: "quit",
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
@@ -140,35 +123,24 @@ function initMenuBar(win: BrowserWindow) {
|
||||
label: "Quit",
|
||||
accelerator: isWindows ? "Alt+F4" : void 0,
|
||||
visible: isWindows,
|
||||
role: "quit",
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: "Zoom",
|
||||
submenu: [
|
||||
{
|
||||
label: "Zoom in",
|
||||
accelerator: "CmdOrCtrl+Plus",
|
||||
role: "zoomIn"
|
||||
},
|
||||
// Fix for zoom in on keyboards with dedicated + like QWERTZ (or numpad)
|
||||
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
|
||||
{
|
||||
label: "Zoom in",
|
||||
label: "Zoom in (hidden, hack for Qwertz and others)",
|
||||
accelerator: "CmdOrCtrl+=",
|
||||
role: "zoomIn",
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
label: "Zoom out",
|
||||
accelerator: "CmdOrCtrl+-",
|
||||
role: "zoomOut"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{ role: "fileMenu" },
|
||||
{ role: "editMenu" },
|
||||
{ role: "viewMenu" },
|
||||
{ role: "windowMenu" }
|
||||
]);
|
||||
|
||||
Menu.setApplicationMenu(menu);
|
||||
@@ -244,7 +216,7 @@ function initSettingsListeners(win: BrowserWindow) {
|
||||
});
|
||||
}
|
||||
|
||||
export function createMainWindow() {
|
||||
function createMainWindow() {
|
||||
const win = (mainWin = new BrowserWindow({
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
@@ -257,6 +229,7 @@ export function createMainWindow() {
|
||||
},
|
||||
icon: ICON_PATH,
|
||||
frame: VencordSettings.store.frameless !== true,
|
||||
...(Settings.store.staticTitle ? { title: "Vencord" } : {}),
|
||||
...(VencordSettings.store.macosTranslucency
|
||||
? {
|
||||
vibrancy: "sidebar",
|
||||
@@ -275,12 +248,18 @@ export function createMainWindow() {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());
|
||||
|
||||
initWindowBoundsListeners(win);
|
||||
if (Settings.store.tray ?? true) initTray(win);
|
||||
initMenuBar(win);
|
||||
makeLinksOpenExternally(win);
|
||||
initSettingsListeners(win);
|
||||
|
||||
win.webContents.setUserAgent(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
|
||||
);
|
||||
|
||||
const subdomain =
|
||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||
? `${Settings.store.discordBranch}.`
|
||||
@@ -290,3 +269,25 @@ export function createMainWindow() {
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
|
||||
|
||||
export async function createWindows() {
|
||||
const splash = createSplashWindow();
|
||||
|
||||
await ensureVencordFiles();
|
||||
runVencordMain();
|
||||
|
||||
mainWin = createMainWindow();
|
||||
|
||||
mainWin.once("ready-to-show", () => {
|
||||
splash.destroy();
|
||||
mainWin!.show();
|
||||
|
||||
if (Settings.store.maximized) {
|
||||
mainWin!.maximize();
|
||||
}
|
||||
});
|
||||
|
||||
initArRPC();
|
||||
}
|
||||
|
||||
@@ -6,18 +6,11 @@
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { STATIC_DIR } from "shared/paths";
|
||||
|
||||
export function createSplashWindow() {
|
||||
const splash = new BrowserWindow({
|
||||
transparent: true,
|
||||
frame: false,
|
||||
height: 350,
|
||||
width: 300,
|
||||
center: true,
|
||||
resizable: false,
|
||||
maximizable: false
|
||||
});
|
||||
const splash = new BrowserWindow(SplashProps);
|
||||
|
||||
splash.loadFile(join(STATIC_DIR, "splash.html"));
|
||||
|
||||
|
||||
@@ -5,32 +5,43 @@
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync } from "fs";
|
||||
import type { RequestOptions } from "https";
|
||||
import { join } from "path";
|
||||
|
||||
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
||||
import { downloadFile, simpleGet } from "./http";
|
||||
|
||||
const API_BASE = "https://api.github.com/repos/Vendicated/Vencord";
|
||||
const API_BASE = "https://api.github.com";
|
||||
|
||||
const FILES_TO_DOWNLOAD = ["vencordDesktopMain.js", "preload.js", "vencordDesktopRenderer.js", "renderer.css"];
|
||||
|
||||
export interface ReleaseData {
|
||||
name: string;
|
||||
tag_name: string;
|
||||
html_url: string;
|
||||
assets: Array<{
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export async function githubGet(endpoint: string) {
|
||||
return simpleGet(API_BASE + endpoint, {
|
||||
const opts: RequestOptions = {
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
"User-Agent": USER_AGENT
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (process.env.GITHUB_TOKEN) opts.headers!.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||
|
||||
return simpleGet(API_BASE + endpoint, opts);
|
||||
}
|
||||
|
||||
export async function downloadVencordFiles() {
|
||||
const release = await githubGet("/releases/latest");
|
||||
const release = await githubGet("/repos/Vendicated/Vencord/releases/latest");
|
||||
|
||||
const data = JSON.parse(release.toString("utf-8"));
|
||||
const assets = data.assets as Array<{
|
||||
name: string;
|
||||
browser_download_url: string;
|
||||
}>;
|
||||
const { assets } = JSON.parse(release.toString("utf-8")) as ReleaseData;
|
||||
|
||||
await Promise.all(
|
||||
assets
|
||||
|
||||
@@ -4,19 +4,11 @@
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import type { Settings } from "shared/settings";
|
||||
import type { LiteralUnion } from "type-fest";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
|
||||
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.invoke(event, ...args) as Promise<T>;
|
||||
}
|
||||
|
||||
function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.sendSync(event, ...args) as T;
|
||||
}
|
||||
import { invoke, sendSync } from "./typedIpcs";
|
||||
|
||||
export const VencordDesktopNative = {
|
||||
app: {
|
||||
@@ -31,6 +23,10 @@ export const VencordDesktopNative = {
|
||||
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
||||
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
|
||||
},
|
||||
spellcheck: {
|
||||
setLanguages: (languages: readonly string[]) => invoke<void>(IpcEvents.SPELLCHECK_SET_LANGUAGES, languages)
|
||||
// todo: perhaps add ways to learn words
|
||||
},
|
||||
win: {
|
||||
focus: () => invoke<void>(IpcEvents.FOCUS)
|
||||
}
|
||||
|
||||
@@ -39,5 +39,6 @@ if (IS_DEV) {
|
||||
document.getElementById("vcd-css-core")!.textContent = readFileSync(rendererCss, "utf-8");
|
||||
});
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
VencordDesktopNative.spellcheck.setLanguages(window.navigator.languages);
|
||||
|
||||
16
src/preload/typedIpcs.ts
Normal file
16
src/preload/typedIpcs.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
|
||||
export function invoke<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.invoke(event, ...args) as Promise<T>;
|
||||
}
|
||||
|
||||
export function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.sendSync(event, ...args) as T;
|
||||
}
|
||||
@@ -6,20 +6,12 @@
|
||||
|
||||
import "./settings.css";
|
||||
|
||||
import { Margins } from "@vencord/types/utils";
|
||||
import { Button, Forms, Select, Switch, Text } from "@vencord/types/webpack/common";
|
||||
import { useSettings } from "renderer/settings";
|
||||
|
||||
import { Common, Util } from "../vencord";
|
||||
|
||||
const { Margins } = Util;
|
||||
|
||||
export default function SettingsUi() {
|
||||
const Settings = useSettings();
|
||||
const {
|
||||
Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle },
|
||||
Text,
|
||||
Select,
|
||||
Button
|
||||
} = Common;
|
||||
|
||||
const switches: [keyof typeof Settings, string, string, boolean?, (() => boolean)?][] = [
|
||||
["tray", "Tray Icon", "Add a tray icon for Vencord Desktop", true],
|
||||
@@ -30,6 +22,7 @@ export default function SettingsUi() {
|
||||
true,
|
||||
() => Settings.tray ?? true
|
||||
],
|
||||
["arRPC", "Rich Presence", "Enables Rich Presence via arRPC", false],
|
||||
[
|
||||
"disableMinSize",
|
||||
"Disable minimum window size",
|
||||
@@ -39,16 +32,17 @@ export default function SettingsUi() {
|
||||
"openLinksWithElectron",
|
||||
"Open Links in app (experimental)",
|
||||
"Opens links in a new Vencord Desktop window instead of your web browser"
|
||||
]
|
||||
],
|
||||
["staticTitle", "Static Title", 'Makes the window title "Vencord" instead of changing to the current page']
|
||||
];
|
||||
|
||||
return (
|
||||
<FormSection>
|
||||
<Forms.FormSection>
|
||||
<Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2">
|
||||
Vencord Desktop Settings
|
||||
</Text>
|
||||
|
||||
<FormTitle className={Margins.top16}>Discord Branch</FormTitle>
|
||||
<Forms.FormTitle className={Margins.top16}>Discord Branch</Forms.FormTitle>
|
||||
<Select
|
||||
placeholder="Stable"
|
||||
options={[
|
||||
@@ -62,22 +56,22 @@ export default function SettingsUi() {
|
||||
serialize={s => s}
|
||||
/>
|
||||
|
||||
<FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||
|
||||
{switches.map(([key, text, note, def, predicate]) => (
|
||||
<FormSwitch
|
||||
value={(Settings[key] ?? def ?? false) && (!predicate || predicate())}
|
||||
<Switch
|
||||
value={(Settings[key as any] ?? def ?? false) && predicate?.() !== false}
|
||||
disabled={predicate && !predicate()}
|
||||
onChange={v => (Settings[key] = v)}
|
||||
onChange={v => (Settings[key as any] = v)}
|
||||
note={note}
|
||||
key={key}
|
||||
>
|
||||
{text}
|
||||
</FormSwitch>
|
||||
</Switch>
|
||||
))}
|
||||
|
||||
<FormTitle>Vencord Location</FormTitle>
|
||||
<FormText>
|
||||
<Forms.FormTitle>Vencord Location</Forms.FormTitle>
|
||||
<Forms.FormText>
|
||||
Vencord files are loaded from{" "}
|
||||
{Settings.vencordDir ? (
|
||||
<a
|
||||
@@ -92,7 +86,7 @@ export default function SettingsUi() {
|
||||
) : (
|
||||
"the default location"
|
||||
)}
|
||||
</FormText>
|
||||
</Forms.FormText>
|
||||
<div className="vcd-location-btns">
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
@@ -117,6 +111,6 @@ export default function SettingsUi() {
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
</FormSection>
|
||||
</Forms.FormSection>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
import "./hideGarbage.css";
|
||||
|
||||
import { waitFor } from "@vencord/types/webpack";
|
||||
|
||||
import { isFirstRun, localStorage } from "./utils";
|
||||
|
||||
// Make clicking Notifications focus the window
|
||||
@@ -25,7 +27,7 @@ if (isFirstRun) {
|
||||
// Hide "Download Discord Desktop now!!!!" banner
|
||||
localStorage.setItem("hideNag", "true");
|
||||
|
||||
Vencord.Webpack.waitFor("setDesktopType", m => {
|
||||
waitFor("setDesktopType", m => {
|
||||
m.setDesktopType("all");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,4 +9,17 @@ import "./fixes";
|
||||
console.log("read if cute :3");
|
||||
|
||||
export * as Components from "./components";
|
||||
export { Settings } from "./settings";
|
||||
import { Settings } from "./settings";
|
||||
export { Settings };
|
||||
|
||||
const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"];
|
||||
|
||||
arRPC.required = !!Settings.store.arRPC;
|
||||
|
||||
Settings.addChangeListener("arRPC", v => {
|
||||
arRPC.required = !!v;
|
||||
if (v && !arRPC.started) Vencord.Plugins.startPlugin(arRPC);
|
||||
else if (arRPC.started) {
|
||||
Vencord.Plugins.stopPlugin(arRPC);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,17 +4,16 @@
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { useEffect, useReducer } from "@vencord/types/webpack/common";
|
||||
import { SettingsStore } from "shared/utils/SettingsStore";
|
||||
|
||||
import { Common } from "./vencord";
|
||||
|
||||
export const Settings = new SettingsStore(VencordDesktopNative.settings.get());
|
||||
Settings.addGlobalChangeListener((o, p) => VencordDesktopNative.settings.set(o, p));
|
||||
|
||||
export function useSettings() {
|
||||
const [, update] = Common.React.useReducer(x => x + 1, 0);
|
||||
const [, update] = useReducer(x => x + 1, 0);
|
||||
|
||||
Common.React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
Settings.addGlobalChangeListener(update);
|
||||
|
||||
return () => Settings.removeGlobalChangeListener(update);
|
||||
|
||||
@@ -19,5 +19,13 @@ export const enum IpcEvents {
|
||||
GET_SETTINGS = "VCD_GET_SETTINGS",
|
||||
SET_SETTINGS = "VCD_SET_SETTINGS",
|
||||
|
||||
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR"
|
||||
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR",
|
||||
|
||||
UPDATER_GET_DATA = "VCD_UPDATER_GET_DATA",
|
||||
UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD",
|
||||
UPDATE_IGNORE = "VCD_UPDATE_IGNORE",
|
||||
|
||||
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
|
||||
|
||||
CLOSE = "VCD_CLOSE"
|
||||
}
|
||||
|
||||
18
src/shared/browserWinProperties.ts
Normal file
18
src/shared/browserWinProperties.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import type { BrowserWindowConstructorOptions } from "electron";
|
||||
|
||||
export const SplashProps: BrowserWindowConstructorOptions = {
|
||||
transparent: true,
|
||||
frame: false,
|
||||
height: 350,
|
||||
width: 300,
|
||||
center: true,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
alwaysOnTop: true
|
||||
};
|
||||
5
src/shared/settings.d.ts
vendored
5
src/shared/settings.d.ts
vendored
@@ -16,4 +16,9 @@ export interface Settings {
|
||||
disableMinSize?: boolean;
|
||||
tray?: boolean;
|
||||
minimizeToTray?: boolean;
|
||||
skippedUpdate?: string;
|
||||
staticTitle?: boolean;
|
||||
arRPC?: boolean;
|
||||
|
||||
firstLaunch?: boolean;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export class SettingsStore<T extends object> {
|
||||
* Set the data of the store.
|
||||
* This will update this.store and this.plain (and old references to them will be stale! Avoid storing them in variables)
|
||||
*
|
||||
* Additionally, all global listeners (or those for pathToNotify, if specified) will be called with the new data
|
||||
* Additionally, all global listeners (and those for pathToNotify, if specified) will be called with the new data
|
||||
* @param value New data
|
||||
* @param pathToNotify Optional path to notify instead of globally. Used to transfer path via ipc
|
||||
*/
|
||||
@@ -90,9 +90,9 @@ export class SettingsStore<T extends object> {
|
||||
}
|
||||
|
||||
this.pathListeners.get(pathToNotify)?.forEach(cb => cb(v));
|
||||
} else {
|
||||
this.globalListeners.forEach(cb => cb(value, ""));
|
||||
}
|
||||
|
||||
this.globalListeners.forEach(cb => cb(value, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
105
src/updater/main.ts
Normal file
105
src/updater/main.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, BrowserWindow, ipcMain, shell } from "electron";
|
||||
import { Settings } from "main/settings";
|
||||
import { githubGet, ReleaseData } from "main/utils/vencordLoader";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
import { STATIC_DIR } from "shared/paths";
|
||||
|
||||
export interface UpdateData {
|
||||
currentVersion: string;
|
||||
latestVersion: string;
|
||||
release: ReleaseData;
|
||||
}
|
||||
|
||||
let updateData: UpdateData;
|
||||
|
||||
ipcMain.handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
|
||||
ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => {
|
||||
const portable = !!process.env.PORTABLE_EXECUTABLE_FILE;
|
||||
|
||||
const { assets } = updateData.release;
|
||||
const url = (() => {
|
||||
switch (process.platform) {
|
||||
case "win32":
|
||||
return assets.find(a => {
|
||||
if (!a.name.endsWith(".exe")) return false;
|
||||
|
||||
const isSetup = a.name.includes("Setup");
|
||||
return portable ? !isSetup : isSetup;
|
||||
})!.browser_download_url;
|
||||
case "darwin":
|
||||
return assets.find(a => a.name.endsWith(".dmg"))!.browser_download_url;
|
||||
case "linux":
|
||||
return updateData.release.html_url;
|
||||
default:
|
||||
throw new Error(`Unsupported platform: ${process.platform}`);
|
||||
}
|
||||
})();
|
||||
|
||||
shell.openExternal(url);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.UPDATE_IGNORE, () => {
|
||||
Settings.store.skippedUpdate = updateData.latestVersion;
|
||||
});
|
||||
|
||||
function isOutdated(oldVersion: string, newVersion: string) {
|
||||
const oldParts = oldVersion.split(".");
|
||||
const newParts = newVersion.split(".");
|
||||
|
||||
if (oldParts.length !== newParts.length)
|
||||
throw new Error(`Incompatible version strings (old: ${oldVersion}, new: ${newVersion})`);
|
||||
|
||||
for (let i = 0; i < oldParts.length; i++) {
|
||||
const oldPart = Number(oldParts[i]);
|
||||
const newPart = Number(newParts[i]);
|
||||
|
||||
if (isNaN(oldPart) || isNaN(newPart))
|
||||
throw new Error(`Invalid version string (old: ${oldVersion}, new: ${newVersion})`);
|
||||
|
||||
if (oldPart < newPart) return true;
|
||||
if (oldPart > newPart) return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function checkUpdates() {
|
||||
// if (IS_DEV) return;
|
||||
try {
|
||||
const raw = await githubGet("/repos/Vencord/Desktop/releases/latest");
|
||||
const data = JSON.parse(raw.toString("utf-8")) as ReleaseData;
|
||||
|
||||
const oldVersion = app.getVersion();
|
||||
const newVersion = data.tag_name.replace(/^v/, "");
|
||||
if (Settings.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) {
|
||||
updateData = {
|
||||
currentVersion: oldVersion,
|
||||
latestVersion: newVersion,
|
||||
release: data
|
||||
};
|
||||
|
||||
openNewUpdateWindow();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("AppUpdater: Failed to check for updates\n", e);
|
||||
}
|
||||
}
|
||||
|
||||
function openNewUpdateWindow() {
|
||||
const win = new BrowserWindow({
|
||||
...SplashProps,
|
||||
webPreferences: {
|
||||
preload: join(__dirname, "updaterPreload.js")
|
||||
}
|
||||
});
|
||||
|
||||
win.loadFile(join(STATIC_DIR, "updater.html"));
|
||||
}
|
||||
21
src/updater/preload.ts
Normal file
21
src/updater/preload.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { contextBridge } from "electron";
|
||||
import { invoke } from "preload/typedIpcs";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
|
||||
import type { UpdateData } from "./main";
|
||||
|
||||
contextBridge.exposeInMainWorld("Updater", {
|
||||
getData: () => invoke<UpdateData>(IpcEvents.UPDATER_GET_DATA),
|
||||
download: () => {
|
||||
invoke<void>(IpcEvents.UPDATER_DOWNLOAD);
|
||||
invoke<void>(IpcEvents.CLOSE);
|
||||
},
|
||||
ignore: () => invoke<void>(IpcEvents.UPDATE_IGNORE),
|
||||
close: () => invoke<void>(IpcEvents.CLOSE)
|
||||
});
|
||||
@@ -13,7 +13,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>About Vencord Desktop</h1>
|
||||
<h1>Vencord Desktop %VERSION%</h1>
|
||||
<p>
|
||||
Vencord Desktop is a free/libre cross platform desktop app aiming to give you a snappier Discord experience with
|
||||
Vencord pre-installed
|
||||
|
||||
125
static/first-launch.html
Normal file
125
static/first-launch.html
Normal file
@@ -0,0 +1,125 @@
|
||||
<head>
|
||||
<style>
|
||||
:root {
|
||||
--bg: white;
|
||||
--fg: black;
|
||||
--fg-semi-trans: rgb(0 0 0 / 0.2);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: hsl(223 6.7% 20.6%);
|
||||
--fg: white;
|
||||
--fg-semi-trans: rgb(255 255 255 / 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100vh;
|
||||
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 1.5em;
|
||||
padding-bottom: 1em;
|
||||
|
||||
border: 1px solid var(--fg-semi-trans);
|
||||
border-top: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
select {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 0.3em;
|
||||
margin: -0.3em;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0.4em 0 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0 2em;
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
gap: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#buttons {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
gap: 0.5em;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.6em;
|
||||
background: red;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#submit {
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Welcome to Vencord Desktop</h1>
|
||||
<p>Let's customise your experience!</p>
|
||||
|
||||
<form>
|
||||
<label>
|
||||
Discord Branch
|
||||
<select name="discordBranch">
|
||||
<option value="stable">stable</option>
|
||||
<option value="canary">canary</option>
|
||||
<option value="ptb">ptb</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Import Settings from existing Vencord install (if found)
|
||||
<input type="checkbox" name="importSettings" checked />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Minimise to Tray when closing
|
||||
<input type="checkbox" name="minimizeToTray" checked />
|
||||
</label>
|
||||
</form>
|
||||
<div id="buttons">
|
||||
<button id="cancel">Cancel</button>
|
||||
<button id="submit">Submit</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
cancel.onclick = () => console.info("cancel");
|
||||
submit.onclick = e => {
|
||||
const form = document.querySelector("form");
|
||||
const formData = new FormData(form);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
console.info("form:" + JSON.stringify(data));
|
||||
e.preventDefault();
|
||||
};
|
||||
</script>
|
||||
115
static/updater.html
Normal file
115
static/updater.html
Normal file
@@ -0,0 +1,115 @@
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgb(219, 222, 225);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
background-color: #313338;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #248046;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5em;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
padding: 0.5em;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-weight: bold;
|
||||
transition: filter 0.2 ease-in-out;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:active {
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #248046;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: #ed4245;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<section>
|
||||
<h1>Update Available</h1>
|
||||
<p>There's a new update for Vencord Desktop! Update now to get new fixes and features!</p>
|
||||
<p>
|
||||
Current: <span id="current"></span>
|
||||
<br />
|
||||
Latest: <span id="latest"></span>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<label id="disable-remind">
|
||||
<input type="checkbox" />
|
||||
<span>Do not remind again for </span>
|
||||
</label>
|
||||
|
||||
<div class="buttons">
|
||||
<button name="download" class="green">Download Update</button>
|
||||
<button name="close" class="red">Close</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="module">
|
||||
const data = await Updater.getData();
|
||||
document.getElementById("current").textContent = data.currentVersion;
|
||||
document.getElementById("latest").textContent = data.latestVersion;
|
||||
|
||||
document.querySelector("#disable-remind > span").textContent += data.latestVersion;
|
||||
|
||||
function checkDisableRemind() {
|
||||
const checkbox = document.querySelector("#disable-remind > input");
|
||||
if (checkbox.checked) {
|
||||
Updater.ignore();
|
||||
}
|
||||
}
|
||||
|
||||
const onClicks = {
|
||||
download() {
|
||||
checkDisableRemind();
|
||||
Updater.download();
|
||||
},
|
||||
close() {
|
||||
checkDisableRemind();
|
||||
Updater.close();
|
||||
}
|
||||
};
|
||||
|
||||
for (const name in onClicks) {
|
||||
document.querySelectorAll(`button[name="${name}"]`).forEach(button => {
|
||||
button.addEventListener("click", onClicks[name]);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -10,7 +10,12 @@
|
||||
"target": "ESNEXT",
|
||||
"jsx": "preserve",
|
||||
|
||||
"baseUrl": "./src/"
|
||||
// we have duplicate electron types but it's w/e
|
||||
"skipLibCheck": true,
|
||||
|
||||
"baseUrl": "./src/",
|
||||
|
||||
"typeRoots": ["./node_modules/@types", "./node_modules/@vencord"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user