9 Commits

Author SHA1 Message Date
V
c31eb8154b Bump to v0.2.2 2023-06-21 20:53:28 +02:00
V
253277984b Add ScreenSharing (#14) 2023-06-21 20:52:56 +02:00
V
23c0647e6c Fix ENOENT on first install 2023-06-21 17:24:50 +02:00
V
fd45068a46 autoStart: respect XDG_CONFIG_HOME 2023-06-21 17:09:04 +02:00
V
9f9f665ede blehhhhh 2023-06-21 16:53:04 +02:00
V
fd0055032f Add AutoStart to first launch tour 2023-06-21 16:52:28 +02:00
V
a993d34c9d autostart: improve typing 2023-06-21 16:15:57 +02:00
V
f232defd1c Add start with system option 2023-06-21 16:13:20 +02:00
V
887f11ab37 About page: Add Acknowledgements 2023-06-21 15:06:06 +02:00
18 changed files with 628 additions and 31 deletions

View File

@@ -9,6 +9,12 @@
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

View File

@@ -5,7 +5,6 @@ Vencord Desktop is a cross platform desktop app aiming to give you a snappier Di
Vencord Desktop is currently in beta
**Not yet supported**:
- Screensharing
- Global Keybinds
Bug reports, feature requests & contributions are highly appreciated!!

View File

@@ -1,6 +1,6 @@
{
"name": "VencordDesktop",
"version": "0.2.1",
"version": "0.2.2",
"private": true,
"description": "",
"keywords": [],
@@ -22,6 +22,9 @@
"testTypes": "tsc --noEmit",
"watch": "pnpm build --watch"
},
"dependencies": {
"arrpc": "^3.1.0"
},
"devDependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
"@types/node": "^18.15.11",
@@ -105,8 +108,5 @@
"provider": "github",
"releaseType": "release"
}
},
"dependencies": {
"arrpc": "^3.1.0"
}
}

49
src/main/autoStart.ts Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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 { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
import { join } from "path";
interface AutoStart {
isEnabled(): boolean;
enable(): void;
disable(): void;
}
function makeAutoStartLinux(): AutoStart {
const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config");
const dir = join(configDir, "autostart");
const file = join(dir, "vencord.desktop");
return {
isEnabled: () => existsSync(file),
enable() {
const desktopFile = `
[Desktop Entry]
Type=Application
Version=1.0
Name=Vencord
Comment=Vencord autostart script
Exec=${process.execPath}
Terminal=false
StartupNotify=false
`.trim();
mkdirSync(dir, { recursive: true });
writeFileSync(file, desktopFile);
},
disable: () => rmSync(file, { force: true })
};
}
const autoStartWindowsMac: AutoStart = {
isEnabled: () => app.getLoginItemSettings().openAtLogin,
enable: () => app.setLoginItemSettings({ openAtLogin: true }),
disable: () => app.setLoginItemSettings({ openAtLogin: false })
};
export const autoStart = process.platform === "linux" ? makeAutoStartLinux() : autoStartWindowsMac;

View File

@@ -11,16 +11,24 @@ import { join } from "path";
import { SplashProps } from "shared/browserWinProperties";
import { STATIC_DIR } from "shared/paths";
import { autoStart } from "./autoStart";
import { DATA_DIR } from "./constants";
import { createWindows } from "./mainWindow";
import { Settings } from "./settings";
interface Data {
minimizeToTray: boolean;
discordBranch: "stable" | "canary" | "ptb";
autoStart: boolean;
importSettings: boolean;
}
export function createFirstLaunchTour() {
const win = new BrowserWindow({
...SplashProps,
frame: true,
autoHideMenuBar: true,
height: 320,
height: 420,
width: 550
});
@@ -29,12 +37,14 @@ export function createFirstLaunchTour() {
if (msg === "cancel") return app.exit();
if (!msg.startsWith("form:")) return;
const data = JSON.parse(msg.slice(5));
const data = JSON.parse(msg.slice(5)) as Data;
Settings.store.minimizeToTray = data.minimizeToTray;
Settings.store.discordBranch = data.discordBranch;
Settings.store.firstLaunch = false;
if (data.autoStart) autoStart.enable();
if (data.importSettings) {
const from = join(app.getPath("userData"), "..", "Vencord", "settings");
const to = join(DATA_DIR, "settings");

View File

@@ -13,6 +13,7 @@ import { ICON_PATH } from "../shared/paths";
import { DATA_DIR } from "./constants";
import { createFirstLaunchTour } from "./firstLaunch";
import { createWindows, mainWin } from "./mainWindow";
import { registerScreenShareHandler } from "./screenShare";
import { Settings } from "./settings";
if (IS_DEV) {
@@ -51,6 +52,7 @@ function init() {
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.desktop");
else if (process.platform === "darwin") app.dock.setIcon(ICON_PATH);
registerScreenShareHandler();
bootstrap();
app.on("activate", () => {

View File

@@ -11,6 +11,7 @@ import { join } from "path";
import { debounce } from "shared/utils/debounce";
import { IpcEvents } from "../shared/IpcEvents";
import { autoStart } from "./autoStart";
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE } from "./constants";
import { mainWin } from "./mainWindow";
import { Settings } from "./settings";
@@ -39,6 +40,12 @@ ipcMain.on(IpcEvents.GET_VERSION, e => {
e.returnValue = app.getVersion();
});
ipcMain.on(IpcEvents.AUTOSTART_ENABLED, e => {
e.returnValue = autoStart.isEnabled();
});
ipcMain.handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable);
ipcMain.handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable);
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => {
Settings.setData(settings, path);
});

55
src/main/screenShare.ts Normal file
View File

@@ -0,0 +1,55 @@
/*
* 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 { desktopCapturer, ipcMain, session, Streams } from "electron";
import type { StreamPick } from "renderer/components/ScreenSharePicker";
import { IpcEvents } from "shared/IpcEvents";
export function registerScreenShareHandler() {
ipcMain.handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
const sources = await desktopCapturer.getSources({
types: ["window", "screen"],
thumbnailSize: {
width: 1920,
height: 1080
}
});
return sources.find(s => s.id === id)?.thumbnail.toDataURL();
});
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
const sources = await desktopCapturer.getSources({
types: ["window", "screen"],
thumbnailSize: {
width: 176,
height: 99
}
});
const data = sources.map(({ id, name, thumbnail }) => ({
id,
name,
url: thumbnail.toDataURL()
}));
const choice = await request.frame
.executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
.then(e => e as StreamPick)
.catch(() => null);
if (!choice) return callback({});
const source = sources.find(s => s.id === choice.id);
if (!source) return callback({});
const streams: Streams = {
video: source
};
if (choice.audio && process.platform === "win32") streams.audio = "loopback";
callback(streams);
});
}

View File

@@ -4,8 +4,8 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { readFileSync, writeFileSync } from "fs";
import { join } from "path";
import { mkdirSync, readFileSync, writeFileSync } from "fs";
import { dirname, join } from "path";
import type { Settings as TSettings } from "shared/settings";
import { SettingsStore } from "shared/utils/SettingsStore";
@@ -25,7 +25,10 @@ function loadSettings<T extends object = any>(file: string, name: string) {
} catch {}
const store = new SettingsStore(settings);
store.addGlobalChangeListener(o => writeFileSync(file, JSON.stringify(o, null, 4)));
store.addGlobalChangeListener(o => {
mkdirSync(dirname(file), { recursive: true });
writeFileSync(file, JSON.stringify(o, null, 4));
});
return store;
}

View File

@@ -15,6 +15,11 @@ export const VencordDesktopNative = {
relaunch: () => invoke<void>(IpcEvents.RELAUNCH),
getVersion: () => sendSync<void>(IpcEvents.GET_VERSION)
},
autostart: {
isEnabled: () => sendSync<boolean>(IpcEvents.AUTOSTART_ENABLED),
enable: () => invoke<void>(IpcEvents.ENABLE_AUTOSTART),
disable: () => invoke<void>(IpcEvents.DISABLE_AUTOSTART)
},
fileManager: {
showItemInFolder: (path: string) => invoke<void>(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
selectVencordDir: () => invoke<LiteralUnion<"cancelled" | "invalid", string>>(IpcEvents.SELECT_VENCORD_DIR)
@@ -29,5 +34,8 @@ export const VencordDesktopNative = {
},
win: {
focus: () => invoke<void>(IpcEvents.FOCUS)
},
capturer: {
getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
}
};

View File

@@ -0,0 +1,225 @@
/*
* 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 "./screenSharePicker.css";
import { classes, closeModal, Margins, Modals, openModal, useAwaiter } from "@vencord/types/utils";
import { findByPropsLazy } from "@vencord/types/webpack";
import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common";
import type { Dispatch, SetStateAction } from "react";
import { isWindows } from "renderer/utils";
const StreamResolutions = ["720", "1080", "1440", "Source"] as const;
const StreamFps = ["15", "30", "60"] as const;
const WarningIconClasses = findByPropsLazy("warning", "error", "container");
export type StreamResolution = (typeof StreamResolutions)[number];
export type StreamFps = (typeof StreamFps)[number];
interface StreamSettings {
resolution: StreamResolution;
fps: StreamFps;
audio: boolean;
}
export interface StreamPick extends StreamSettings {
id: string;
}
interface Source {
id: string;
name: string;
url: string;
}
export function openScreenSharePicker(screens: Source[]) {
return new Promise<StreamPick>((resolve, reject) => {
const key = openModal(
props => (
<ModalComponent
screens={screens}
modalProps={props}
submit={resolve}
close={() => {
props.onClose();
reject("Aborted");
}}
/>
),
{
onCloseRequest() {
closeModal(key);
reject("Aborted");
}
}
);
});
}
function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScreen: (id: string) => void }) {
return (
<div className="vcd-screen-picker-grid">
{screens.map(({ id, name, url }) => (
<label key={id}>
<input type="radio" name="screen" value={id} onChange={() => chooseScreen(id)} />
<img src={url} alt="" />
<Text variant="text-sm/normal">{name}</Text>
</label>
))}
</div>
);
}
function StreamSettings({
source,
settings,
setSettings
}: {
source: Source;
settings: StreamSettings;
setSettings: Dispatch<SetStateAction<StreamSettings>>;
}) {
const [thumb] = useAwaiter(() => VencordDesktopNative.capturer.getLargeThumbnail(source.id), {
fallbackValue: source.url,
deps: [source.id]
});
return (
<div>
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
<Card className="vcd-screen-picker-card vcd-screen-picker-preview">
<img src={thumb} alt="" />
<Text variant="text-sm/normal">{source.name}</Text>
</Card>
<Forms.FormTitle>Stream Settings</Forms.FormTitle>
<Card className="vcd-screen-picker-card">
<Card className={classes(WarningIconClasses.container, WarningIconClasses.warning, Margins.bottom8)}>
<Forms.FormText>
Resolution and Frame Rate aren't implemented for now. Locked to 720p 30fps
</Forms.FormText>
</Card>
<div className="vcd-screen-picker-quality">
<section>
<Forms.FormTitle>Resolution</Forms.FormTitle>
<div className="vcd-screen-picker-radios">
{StreamResolutions.map(res => (
<label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}>
<Text variant="text-sm/bold">{res}</Text>
<input
type="radio"
name="resolution"
value={res}
checked={settings.resolution === res}
onChange={() => setSettings(s => ({ ...s, resolution: res }))}
/>
</label>
))}
</div>
</section>
<section>
<Forms.FormTitle>Frame Rate</Forms.FormTitle>
<div className="vcd-screen-picker-radios">
{StreamFps.map(fps => (
<label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}>
<Text variant="text-sm/bold">{fps}</Text>
<input
type="radio"
name="fps"
value={fps}
checked={settings.fps === fps}
onChange={() => setSettings(s => ({ ...s, fps }))}
/>
</label>
))}
</div>
</section>
</div>
{isWindows && (
<Switch
value={settings.audio}
onChange={checked => setSettings(s => ({ ...s, audio: checked }))}
hideBorder
className="vcd-screen-picker-audio"
>
Stream With Audio
</Switch>
)}
</Card>
</div>
);
}
function ModalComponent({
screens,
modalProps,
submit,
close
}: {
screens: Source[];
modalProps: any;
submit: (data: StreamPick) => void;
close: () => void;
}) {
const [selected, setSelected] = useState<string>();
const [settings, setSettings] = useState<StreamSettings>({
resolution: "1080",
fps: "60",
audio: true
});
return (
<Modals.ModalRoot {...modalProps}>
<Modals.ModalHeader className="vcd-screen-picker-header">
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
<Modals.ModalCloseButton onClick={close} />
</Modals.ModalHeader>
<Modals.ModalContent className="vcd-screen-picker-modal">
{!selected ? (
<ScreenPicker screens={screens} chooseScreen={setSelected} />
) : (
<StreamSettings
source={screens.find(s => s.id === selected)!}
settings={settings}
setSettings={setSettings}
/>
)}
</Modals.ModalContent>
<Modals.ModalFooter className="vcd-screen-picker-footer">
<Button
disabled={!selected}
onClick={() => {
submit({
id: selected!,
...settings
});
close();
}}
>
Go Live
</Button>
{selected ? (
<Button color={Button.Colors.TRANSPARENT} onClick={() => setSelected(void 0)}>
Back
</Button>
) : (
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
Cancel
</Button>
)}
</Modals.ModalFooter>
</Modals.ModalRoot>
);
}

View File

@@ -7,12 +7,15 @@
import "./settings.css";
import { Margins } from "@vencord/types/utils";
import { Button, Forms, Select, Switch, Text } from "@vencord/types/webpack/common";
import { Button, Forms, Select, Switch, Text, useState } from "@vencord/types/webpack/common";
import { useSettings } from "renderer/settings";
export default function SettingsUi() {
const Settings = useSettings();
const { autostart } = VencordDesktopNative;
const [autoStartEnabled, setAutoStartEnabled] = useState(autostart.isEnabled());
const switches: [keyof typeof Settings, string, string, boolean?, (() => boolean)?][] = [
["tray", "Tray Icon", "Add a tray icon for Vencord Desktop", true],
[
@@ -58,6 +61,17 @@ export default function SettingsUi() {
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
<Switch
value={autoStartEnabled}
onChange={async v => {
await autostart[v ? "enable" : "disable"]();
setAutoStartEnabled(v);
}}
note="Automatically start Vencord Desktop on computer start-up"
>
Start With System
</Switch>
{switches.map(([key, text, note, def, predicate]) => (
<Switch
value={(Settings[key as any] ?? def ?? false) && predicate?.() !== false}

View File

@@ -4,4 +4,5 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
export * as ScreenShare from "./ScreenSharePicker";
export { default as Settings } from "./Settings";

View File

@@ -0,0 +1,126 @@
.vcd-screen-picker-modal {
padding: 1em;
}
.vcd-screen-picker-header h1 {
margin: 0;
}
.vcd-screen-picker-footer {
display: flex;
gap: 1em;
}
.vcd-screen-picker-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2em 1em;
}
.vcd-screen-picker-grid input {
appearance: none;
cursor: pointer;
}
.vcd-screen-picker-selected img {
border: 2px solid var(--brand-experiment);
border-radius: 3px;
}
.vcd-screen-picker-grid label {
overflow: hidden;
padding: 4px 0px;
cursor: pointer;
}
.vcd-screen-picker-grid label:hover {
outline: 2px solid var(--brand-experiment);
}
.vcd-screen-picker-grid div {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-align: center;
font-weight: 600;
margin-inline: 0.5em;
}
.vcd-screen-picker-card {
padding: 0.5em;
box-sizing: border-box;
}
.vcd-screen-picker-preview img {
width: 100%;
margin-bottom: 0.5em;
}
.vcd-screen-picker-preview {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 1em;
}
.vcd-screen-picker-radio input {
display: none;
}
.vcd-screen-picker-radio {
background-color: var(--background-secondary);
border: 1px solid var(--primary-800);
padding: 0.3em;
cursor: pointer;
}
.vcd-screen-picker-radio h2 {
margin: 0;
}
.vcd-screen-picker-radio[data-checked="true"] {
background-color: var(--brand-experiment);
border-color: var(--brand-experiment);
}
.vcd-screen-picker-radio[data-checked="true"] h2 {
color: var(--interactive-active);
}
.vcd-screen-picker-quality {
display: flex;
gap: 1em;
margin-bottom: 0.5em;
opacity: 0.3;
}
.vcd-screen-picker-quality section {
flex: 1 1 auto;
}
.vcd-screen-picker-radios {
display: flex;
width: 100%;
border-radius: 3px;
}
.vcd-screen-picker-radios label {
flex: 1 1 auto;
text-align: center;
}
.vcd-screen-picker-radios label:first-child {
border-radius: 3px 0 0 3px;
}
.vcd-screen-picker-radios label:last-child {
border-radius: 0 3px 3px 0;
}
.vcd-screen-picker-audio {
margin-bottom: 0;
}

View File

@@ -12,3 +12,7 @@ export const isFirstRun = (() => {
localStorage.setItem(key, "false");
return true;
})();
const { platform } = navigator;
export const isWindows = platform.startsWith("Win");

View File

@@ -10,11 +10,12 @@ export const enum IpcEvents {
GET_RENDERER_SCRIPT = "VCD_GET_RENDERER_SCRIPT",
GET_RENDERER_CSS_FILE = "VCD_GET_RENDERER_CSS_FILE",
RELAUNCH = "VCD_RELAUNCH",
FOCUS = "VCD_FOCUS",
GET_VERSION = "VCD_GET_VERSION",
RELAUNCH = "VCD_RELAUNCH",
CLOSE = "VCD_CLOSE",
FOCUS = "VCD_FOCUS",
SHOW_ITEM_IN_FOLDER = "VCD_SHOW_ITEM_IN_FOLDER",
GET_SETTINGS = "VCD_GET_SETTINGS",
SET_SETTINGS = "VCD_SET_SETTINGS",
@@ -27,5 +28,9 @@ export const enum IpcEvents {
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
CLOSE = "VCD_CLOSE"
CAPTURER_GET_LARGE_THUMBNAIL = "VCD_CAPTURER_GET_LARGE_THUMBNAIL",
AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED",
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART"
}

View File

@@ -19,16 +19,44 @@
Vencord pre-installed
</p>
<h2>Links</h2>
<ul>
<li>
<a href="https://vencord.dev">Vencord Website</a>
</li>
<li>
<a href="https://github.com/Vencord/Desktop" target="_blank">Source Code</a>
</li>
<li>
<a href="https://github.com/Vencord/Desktop/issues" target="_blank">Report bugs / Request features</a>
</li>
</ul>
<section>
<h2>Links</h2>
<ul>
<li>
<a href="https://vencord.dev" target="_blank">Vencord Website</a>
</li>
<li>
<a href="https://github.com/Vencord/Desktop" target="_blank">Source Code</a>
</li>
<li>
<a href="https://github.com/Vencord/Desktop/issues" target="_blank">Report bugs / Request features</a>
</li>
</ul>
</section>
<section>
<h2>Acknowledgements</h2>
<p>These awesome libraries empower Vencord Desktop</p>
<ul>
<li>
<a href="https://github.com/electron/electron" target="_blank">Electron</a>
- Build cross-platform desktop apps with JavaScript, HTML, and CSS
</li>
<li>
<a href="https://github.com/electron-userland/electron-builder" target="_blank">Electron Builder</a>
- A complete solution to package and build a ready for distribution Electron app with “auto update”
support out of the box
</li>
<li>
<a href="https://github.com/OpenAsar/arrpc" target="_blank">arrpc</a>
- An open implementation of Discord's Rich Presence server
</li>
<li>
And many
<a href="https://github.com/Vencord/Desktop/blob/main/pnpm-lock.yaml" target="_blank"
>more awesome open source libraries</a
>
</li>
</ul>
</section>
</body>

View File

@@ -3,6 +3,7 @@
:root {
--bg: white;
--fg: black;
--fg-secondary: #313338;
--fg-semi-trans: rgb(0 0 0 / 0.2);
}
@@ -10,6 +11,7 @@
:root {
--bg: hsl(223 6.7% 20.6%);
--fg: white;
--fg-secondary: #b5bac1;
--fg-semi-trans: rgb(255 255 255 / 0.2);
}
}
@@ -52,15 +54,49 @@
form {
display: grid;
gap: 0.5em;
gap: 1em;
margin: 0;
}
label {
position: relative;
display: flex;
justify-content: space-between;
}
label:has(input[type="checkbox"]),
select {
cursor: pointer;
}
label:not(:last-child)::after {
content: "";
position: absolute;
bottom: -10px;
width: 100%;
height: 1px;
background-color: var(--fg-secondary);
opacity: 0.5;
}
label div {
display: grid;
gap: 0.2em;
}
label h2 {
margin: 0;
font-weight: normal;
font-size: 1.1rem;
line-height: 1rem;
}
label span {
font-size: 0.9rem;
font-weight: 400;
color: var(--fg-secondary);
}
#buttons {
display: flex;
justify-content: end;
@@ -75,6 +111,11 @@
border-radius: 6px;
border: none;
cursor: pointer;
transition: 200ms filter;
}
button:hover {
filter: brightness(0.8);
}
#submit {
@@ -89,7 +130,7 @@
<form>
<label>
Discord Branch
<h2>Discord Branch</h2>
<select name="discordBranch">
<option value="stable">stable</option>
<option value="canary">canary</option>
@@ -98,12 +139,26 @@
</label>
<label>
Import Settings from existing Vencord install (if found)
<div>
<h2>Start with System</h2>
<span>Automatically open Vencord Desktop when your computer starts</span>
</div>
<input type="checkbox" name="autoStart" checked />
</label>
<label>
<div>
<h2>Import Settings</h2>
<span>Import Settings from existing Vencord install (if found)</span>
</div>
<input type="checkbox" name="importSettings" checked />
</label>
<label>
Minimise to Tray when closing
<div>
<h2>Minimise to Tray</h2>
<span>Minimise to Tray when closing</span>
</div>
<input type="checkbox" name="minimizeToTray" checked />
</label>
</form>