7 Commits

Author SHA1 Message Date
Vendicated
5f01dfdbd0 [WP] migrate to new Vencord components 2025-11-20 00:03:47 +01:00
Vendicated
13e7e4491f fix misleading filename 2025-11-18 17:35:21 +01:00
Vendicated
34c92cfb59 fix screenshare picker ui 2025-11-18 17:24:35 +01:00
Vendicated
28aeab979b Upgrade to electron 39.2.1
Fixes https://github.com/Vencord/Vesktop/issues/1204
2025-11-17 22:24:39 +01:00
Vendicated
8ca3e4f3a1 fix potential edge case in cli argument parsing 2025-11-15 11:33:21 +01:00
Vendicated
ae47c204fa fix --start-minimized not working when splash is disabled 2025-11-15 11:29:44 +01:00
Vendicated
f57245f297 fix views using quirks mode & non utf-8 2025-11-03 20:41:33 +01:00
22 changed files with 744 additions and 357 deletions

View File

@@ -36,14 +36,14 @@
"devDependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
"@stylistic/eslint-plugin": "^5.5.0",
"@types/node": "^24.9.1",
"@types/node": "^24.10.1",
"@types/react": "19.2.1",
"@vencord/types": "^1.13.2",
"dotenv": "^17.2.3",
"electron": "^39.0.0",
"electron": "^39.2.1",
"electron-builder": "^26.0.12",
"esbuild": "^0.25.11",
"eslint": "^9.38.0",
"esbuild": "^0.27.0",
"eslint": "^9.39.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-path-alias": "^2.1.0",
"eslint-plugin-prettier": "^5.5.4",
@@ -54,9 +54,9 @@
"prettier": "^3.6.2",
"source-map-support": "^0.5.21",
"tsx": "^4.20.6",
"type-fest": "^5.1.0",
"type-fest": "^5.2.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.2",
"typescript-eslint": "^8.47.0",
"xml-formatter": "^3.6.7"
},
"packageManager": "pnpm@10.7.1",

863
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,9 @@ const extraOptions = {
}
} satisfies Record<string, Option>;
const args = basename(process.argv[0]) === "electron" ? process.argv.slice(2) : process.argv.slice(1);
const args = basename(process.argv[0]).toLowerCase().startsWith("electron")
? process.argv.slice(2)
: process.argv.slice(1);
export const CommandLine = parseArgs({
args,

View File

@@ -31,8 +31,8 @@ export function createFirstLaunchTour() {
transparent: false,
frame: true,
autoHideMenuBar: true,
height: 470,
width: 550
height: 550,
width: 600
});
makeLinksOpenExternally(win);

View File

@@ -319,7 +319,7 @@ function buildBrowserWindowOptions(): BrowserWindowConstructorOptions {
splashTheming !== false ? splashBackground : nativeTheme.shouldUseDarkColors ? "#313338" : "#ffffff";
const options: BrowserWindowConstructorOptions = {
show: Settings.store.enableSplashScreen === false,
show: Settings.store.enableSplashScreen === false && !CommandLine.values["start-minimized"],
backgroundColor,
webPreferences: {
nodeIntegration: false,

View File

@@ -7,16 +7,16 @@
import "./screenSharePicker.css";
import { classNameFactory } from "@vencord/types/api/Styles";
import { FormSwitch } from "@vencord/types/components";
import { closeModal, Logger, Modals, ModalSize, openModal, useAwaiter } from "@vencord/types/utils";
import { Button, Card, CogWheel, FormSwitch, Heading, Paragraph, RestartIcon } from "@vencord/types/components";
import { closeModal, Logger, Modals, ModalSize, openModal, useAwaiter, useForceUpdater } from "@vencord/types/utils";
import { onceReady } from "@vencord/types/webpack";
import { Button, Card, FluxDispatcher, Forms, Select, Text, UserStore, useState } from "@vencord/types/webpack/common";
import { FluxDispatcher, Select, UserStore, useState } from "@vencord/types/webpack/common";
import { Node } from "@vencord/venmic";
import type { Dispatch, SetStateAction } from "react";
import { MediaEngineStore } from "renderer/common";
import { isLinux, isWindows } from "renderer/constants";
import { addPatch } from "renderer/patches/shared";
import { State, useSettings, useVesktopState } from "renderer/settings";
import { isLinux, isWindows } from "renderer/utils";
const StreamResolutions = ["480", "720", "1080", "1440", "2160"] as const;
const StreamFps = ["15", "30", "60"] as const;
@@ -165,9 +165,9 @@ function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScre
/>
<img src={url} alt="" />
<Text className={cl("screen-name")} variant="text-sm/normal">
<Paragraph className={cl("screen-name")} size="sm">
{name}
</Text>
</Paragraph>
</label>
))}
</div>
@@ -188,12 +188,13 @@ function AudioSettingsModal({
return (
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
<Modals.ModalHeader className={cl("header")}>
<Forms.FormTitle tag="h2" className={cl("header-title")}>
<Heading tag="h2" className={cl("header-title")}>
Venmic Settings
</Forms.FormTitle>
<Modals.ModalCloseButton onClick={close} />
</Heading>
<Modals.ModalCloseButton onClick={close} className={cl("header-close-button")} />
</Modals.ModalHeader>
<Modals.ModalContent className={cl("modal")}>
<Modals.ModalContent className={cl("modal", "venmic-settings")}>
<FormSwitch
title="Microphone Workaround"
description={
@@ -290,7 +291,7 @@ function AudioSettingsModal({
/>
</Modals.ModalContent>
<Modals.ModalFooter className={cl("footer")}>
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
<Button variant="secondary" onClick={close}>
Back
</Button>
</Modals.ModalFooter>
@@ -311,7 +312,9 @@ function OptionRadio<Settings extends object, Key extends keyof Settings>(props:
<div className={cl("option-radios")}>
{(options as string[]).map((option, idx) => (
<label className={cl("option-radio")} data-checked={settings[settingsKey] === option} key={option}>
<Text variant="text-sm/bold">{labels?.[idx] ?? option}</Text>
<Paragraph size="sm" weight="bold">
{labels?.[idx] ?? option}
</Paragraph>
<input
className={cl("option-input")}
type="radio"
@@ -349,7 +352,7 @@ function StreamSettingsUi({
);
const openSettings = () => {
const key = openModal(props => (
openModal(props => (
<AudioSettingsModal
modalProps={props}
close={() => props.onClose()}
@@ -362,18 +365,18 @@ function StreamSettingsUi({
return (
<div>
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
<Heading>What you're streaming</Heading>
<Card className={cl("card", "preview")}>
<img src={thumb} alt="" className={cl(isLinux ? "preview-img-linux" : "preview-img")} />
<Text variant="text-sm/normal">{source.name}</Text>
<Paragraph size="sm">{source.name}</Paragraph>
</Card>
<Forms.FormTitle>Stream Settings</Forms.FormTitle>
<Heading>Stream Settings</Heading>
<Card className={cl("card")}>
<div className={cl("quality")}>
<section className={cl("quality-section")}>
<Forms.FormTitle>Resolution</Forms.FormTitle>
<Heading>Resolution</Heading>
<OptionRadio
options={StreamResolutions}
settings={qualitySettings}
@@ -383,7 +386,7 @@ function StreamSettingsUi({
</section>
<section className={cl("quality-section")}>
<Forms.FormTitle>Frame Rate</Forms.FormTitle>
<Heading>Frame Rate</Heading>
<OptionRadio
options={StreamFps}
settings={qualitySettings}
@@ -394,7 +397,7 @@ function StreamSettingsUi({
</div>
<div className={cl("quality")}>
<section className={cl("quality-section")}>
<Forms.FormTitle>Content Type</Forms.FormTitle>
<Heading>Content Type</Heading>
<div>
<OptionRadio
options={["motion", "detail"]}
@@ -568,8 +571,10 @@ function AudioSourcePickerLinux({
setIncludeSources: (s: AudioSources) => void;
setExcludeSources: (s: AudioSources) => void;
}) {
const [audioSourcesSignal, refreshAudioSources] = useForceUpdater(true);
const [sources, _, loading] = useAwaiter(() => VesktopNative.virtmic.list(), {
fallbackValue: { ok: true, targets: [], hasPipewirePulse: true }
fallbackValue: { ok: true, targets: [], hasPipewirePulse: true },
deps: [audioSourcesSignal]
});
const hasPipewirePulse = sources.ok ? sources.hasPipewirePulse : true;
@@ -577,7 +582,7 @@ function AudioSourcePickerLinux({
if (!sources.ok && sources.isGlibCxxOutdated) {
return (
<Forms.FormText>
<Paragraph>
Failed to retrieve Audio Sources because your C++ library is too old to run
<a href="https://github.com/Vencord/venmic" target="_blank">
venmic
@@ -587,13 +592,13 @@ function AudioSourcePickerLinux({
this guide
</a>{" "}
for possible solutions.
</Forms.FormText>
</Paragraph>
);
}
if (!hasPipewirePulse && !ignorePulseWarning) {
return (
<Text variant="text-sm/normal">
<Paragraph size="sm">
Could not find pipewire-pulse. See{" "}
<a href="https://gist.github.com/the-spyke/2de98b22ff4f978ebf0650c90e82027e#install" target="_blank">
this guide
@@ -602,7 +607,7 @@ function AudioSourcePickerLinux({
You can still continue, however, please{" "}
<b>beware that you can only share audio of apps that are running under pipewire</b>.{" "}
<a onClick={() => setIgnorePulseWarning(true)}>I know what I'm doing!</a>
</Text>
</Paragraph>
);
}
@@ -620,9 +625,9 @@ function AudioSourcePickerLinux({
return (
<>
<div className={cl({ quality: includeSources === "Entire System" })}>
<div className={cl("audio-sources")}>
<section>
<Forms.FormTitle>{loading ? "Loading Sources..." : "Audio Sources"}</Forms.FormTitle>
<Heading>{loading ? "Loading Sources..." : "Audio Sources"}</Heading>
<Select
options={allSources.map(({ name, value }) => ({
label: name,
@@ -638,7 +643,7 @@ function AudioSourcePickerLinux({
</section>
{includeSources === "Entire System" && (
<section>
<Forms.FormTitle>Exclude Sources</Forms.FormTitle>
<Heading>Exclude Sources</Heading>
<Select
options={allSources
.filter(x => x.name !== "Entire System")
@@ -656,9 +661,16 @@ function AudioSourcePickerLinux({
</section>
)}
</div>
<Button color={Button.Colors.TRANSPARENT} onClick={openSettings} className={cl("settings-button")}>
Open Audio Settings
</Button>
<div className={cl("settings-buttons")}>
<Button variant="secondary" onClick={refreshAudioSources} className={cl("settings-button")}>
<RestartIcon className={cl("settings-button-icon")} />
Refresh Audio Sources
</Button>
<Button variant="secondary" onClick={openSettings} className={cl("settings-button")}>
<CogWheel className={cl("settings-button-icon")} />
Open Audio Settings
</Button>
</div>
</>
);
}
@@ -690,9 +702,12 @@ function ModalComponent({
return (
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
<Modals.ModalHeader className={cl("header")}>
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
<Modals.ModalCloseButton onClick={close} />
<Heading tag="h2" className={cl("header-title")}>
ScreenShare
</Heading>
<Modals.ModalCloseButton onClick={close} className={cl("header-close-button")} />
</Modals.ModalHeader>
<Modals.ModalContent className={cl("modal")}>
{!selected ? (
<ScreenPicker screens={screens} chooseScreen={setSelected} />
@@ -769,11 +784,11 @@ function ModalComponent({
</Button>
{selected && !skipPicker ? (
<Button color={Button.Colors.TRANSPARENT} onClick={() => setSelected(void 0)}>
<Button variant="secondary" onClick={() => setSelected(void 0)}>
Back
</Button>
) : (
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
<Button variant="secondary" onClick={close}>
Cancel
</Button>
)}

View File

@@ -2,8 +2,13 @@
padding: 1em;
}
.vcd-screen-picker-header-title {
margin: 0;
.vcd-screen-picker-header-close-button {
margin-left: auto;
}
.vcd-screen-picker-venmic-settings {
display: grid;
gap: 8px;
}
.vcd-screen-picker-footer {
@@ -13,9 +18,10 @@
.vcd-screen-picker-card {
flex-grow: 1;
padding: 0.5em;
box-sizing: border-box;
}
/* Screen Grid */
.vcd-screen-picker-screen-grid {
display: grid;
@@ -49,11 +55,6 @@
margin-inline: 0.5em;
}
.vcd-screen-picker-card {
padding: 0.5em;
box-sizing: border-box;
}
.vcd-screen-picker-preview-img-linux {
width: 60%;
margin-bottom: 0.5em;
@@ -117,19 +118,40 @@
flex: 1 1 auto;
}
.vcd-screen-picker-settings-button {
margin-left: auto;
margin-top: 0.3rem;
.vcd-screen-picker-settings-buttons {
display: flex;
justify-content: end;
gap: 0.5em;
margin-top: 0.75em;
}
.vcd-screen-picker-settings-button {
display: flex;
gap: 0.25em;
padding-inline: 0.5em 1em;
}
.vcd-screen-picker-settings-button-icon {
height: 1em;
}
.vcd-screen-picker-audio {
margin-bottom: 0;
}
.vcd-screen-picker-audio-sources {
display: flex;
gap: 1em;
>section {
flex: 1;
}
}
.vcd-screen-picker-hint-description {
color: var(--header-secondary);
font-size: 14px;
line-height: 20px;
font-weight: 400;
}
}

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Heading, Paragraph } from "@vencord/types/components";
import {
Margins,
ModalCloseButton,
@@ -14,7 +15,7 @@ import {
openModal,
useForceUpdater
} from "@vencord/types/utils";
import { Button, Forms, Text, Toasts } from "@vencord/types/webpack/common";
import { Button, Text, Toasts } from "@vencord/types/webpack/common";
import { Settings } from "shared/settings";
import { cl, SettingsComponent } from "./Settings";
@@ -35,12 +36,12 @@ function openDeveloperOptionsModal(settings: Settings) {
<ModalContent>
<div style={{ padding: "1em 0" }}>
<Forms.FormTitle tag="h5">Vencord Location</Forms.FormTitle>
<Heading tag="h5">Vencord Location</Heading>
<VencordLocationPicker settings={settings} />
<Forms.FormTitle tag="h5" className={Margins.top16}>
<Heading tag="h5" className={Margins.top16}>
Debugging
</Forms.FormTitle>
</Heading>
<div className={cl("button-grid")}>
<Button onClick={() => VesktopNative.debug.launchGpu()}>Open chrome://gpu</Button>
<Button onClick={() => VesktopNative.debug.launchWebrtcInternals()}>
@@ -59,7 +60,7 @@ const VencordLocationPicker: SettingsComponent = ({ settings }) => {
return (
<>
<Forms.FormText>
<Paragraph>
Vencord files are loaded from{" "}
{vencordDir ? (
<a
@@ -74,7 +75,7 @@ const VencordLocationPicker: SettingsComponent = ({ settings }) => {
) : (
"the default location"
)}
</Forms.FormText>
</Paragraph>
<div className={cl("button-grid")}>
<Button
size={Button.Sizes.SMALL}

View File

@@ -7,11 +7,11 @@
import "./settings.css";
import { classNameFactory } from "@vencord/types/api/Styles";
import { ErrorBoundary } from "@vencord/types/components";
import { Forms, Text } from "@vencord/types/webpack/common";
import { Divider, ErrorBoundary } from "@vencord/types/components";
import { Text } from "@vencord/types/webpack/common";
import { ComponentType } from "react";
import { isMac, isWindows } from "renderer/constants";
import { Settings, useSettings } from "renderer/settings";
import { isMac, isWindows } from "renderer/utils";
import { AutoStartToggle } from "./AutoStartToggle";
import { DeveloperOptionsButton } from "./DeveloperOptions";
@@ -173,7 +173,7 @@ function SettingsSections() {
})}
</div>
{i < arr.length - 1 && <Forms.FormDivider className={cl("category-divider")} />}
{i < arr.length - 1 && <Divider className={cl("category-divider")} />}
</div>
));

View File

@@ -4,8 +4,9 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Paragraph } from "@vencord/types/components";
import { useAwaiter } from "@vencord/types/utils";
import { Button, Text } from "@vencord/types/webpack/common";
import { Button } from "@vencord/types/webpack/common";
import { cl } from "./Settings";
@@ -16,8 +17,12 @@ export function Updater() {
return (
<div className={cl("updater-card")}>
<Text variant="text-md/semibold">Your Vesktop is outdated!</Text>
<Text variant="text-sm/normal">Staying up to date is important for security and stability.</Text>
<Paragraph size="md" weight="semibold">
Your Vesktop is outdated!
</Paragraph>
<Paragraph size="sm" weight="normal">
Staying up to date is important for security and stability.
</Paragraph>
<Button
onClick={() => VesktopNative.app.openUpdater()}

View File

@@ -6,7 +6,7 @@
import "./UserAssets.css";
import { FormSwitch } from "@vencord/types/components";
import { FormSwitch, Heading } from "@vencord/types/components";
import {
Margins,
ModalCloseButton,
@@ -73,9 +73,7 @@ function Asset({ asset }: { asset: UserAssetType }) {
return (
<section>
<Text tag="h3" variant="text-md/semibold">
{wordsToTitle(wordsFromCamel(asset))}
</Text>
<Heading tag="h3">{wordsToTitle(wordsFromCamel(asset))}</Heading>
<div className="vcd-user-assets-asset">
<img
className="vcd-user-assets-image"

View File

@@ -4,9 +4,9 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { ErrorBoundary } from "@vencord/types/components";
import { ErrorBoundary, Heading, Paragraph } from "@vencord/types/components";
import { Margins } from "@vencord/types/utils";
import { Forms, Select } from "@vencord/types/webpack/common";
import { Select } from "@vencord/types/webpack/common";
import { SettingsComponent } from "./Settings";
@@ -16,10 +16,10 @@ export const WindowsTransparencyControls: SettingsComponent = ({ settings }) =>
return (
<ErrorBoundary noop>
<div>
<Forms.FormTitle className={Margins.bottom8}>Transparency Options</Forms.FormTitle>
<Forms.FormText className={Margins.bottom8}>
<Heading>Transparency Options</Heading>
<Paragraph className={Margins.bottom8}>
Requires a full restart. You will need a theme that supports transparency for this to work.
</Forms.FormText>
</Paragraph>
<Select
placeholder="None"

View File

@@ -4,7 +4,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { localStorage } from "./utils";
import { localStorage } from "./constants";
// Make clicking Notifications focus the window
const originalSetOnClick = Object.getOwnPropertyDescriptor(Notification.prototype, "onclick")!.set!;

View File

@@ -4,8 +4,8 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { isMac } from "renderer/constants";
import { Settings } from "renderer/settings";
import { isMac } from "renderer/utils";
import { addPatch } from "./shared";

View File

@@ -6,8 +6,8 @@
import { Logger } from "@vencord/types/utils";
import { currentSettings } from "renderer/components/ScreenSharePicker";
import { isLinux } from "renderer/constants";
import { State } from "renderer/settings";
import { isLinux } from "renderer/utils";
const logger = new Logger("VesktopStreamFixes");

View File

@@ -7,8 +7,8 @@
import { useEffect, useReducer } from "@vencord/types/webpack/common";
import { SettingsStore } from "shared/utils/SettingsStore";
import { localStorage } from "./constants";
import { VesktopLogger } from "./logger";
import { localStorage } from "./utils";
export const Settings = new SettingsStore(VesktopNative.settings.get());
Settings.addGlobalChangeListener((o, p) => VesktopNative.settings.set(o, p));

View File

@@ -1,3 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
<head>
<title>About Vesktop</title>
@@ -63,7 +66,7 @@
</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
- A complete solution to package and build a ready for distribution Electron app with "auto update"
support out of the box
</li>
<li>

View File

@@ -9,11 +9,15 @@
--link-hover: light-dark(#005bb5, #0086c3);
}
html,
body {
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
"Open Sans", "Helvetica Neue", sans-serif;
margin: 0;
padding: 0;
background: var(--bg);
color: var(--fg);
}

View File

@@ -1,3 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
<head>
<title>Vesktop Setup</title>

View File

@@ -1,7 +1,16 @@
<!doctype html>
<meta charset="utf-8" />
<head>
<link rel="stylesheet" href="./common.css" type="text/css" />
<style>
html,
body {
width: 100%;
height: 100%;
}
body {
background: none;
user-select: none;
@@ -10,8 +19,9 @@
}
.wrapper {
box-sizing: border-box;
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;

View File

@@ -1,3 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
<head>
<title>Vesktop Updater</title>
<meta http-equiv="Content-Security-Policy" content="