This commit is contained in:
thororen1234 2026-04-19 13:35:42 -04:00
parent 2d6baf00db
commit 180059b022
No known key found for this signature in database
20 changed files with 166 additions and 177 deletions

View file

@ -87,6 +87,7 @@ export default defineConfig(
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/spaced-comment": ["error", "always", { "markers": ["!"] }],
"@stylistic/no-extra-semi": "error",
"@stylistic/indent": ["error", 4, { "SwitchCase": 1 }],
"no-multiple-empty-lines": ["error", { "max": 1, "maxBOF": 0, "maxEOF": 0 }],
// TS Rules

View file

@ -384,9 +384,9 @@ type UseSettings<T extends object> = ResolveUseSettings<T>[keyof T];
type ResolveUseSettings<T extends object> = {
[Key in keyof T]:
Key extends string
? T[Key] extends Record<string, unknown>
// @ts-expect-error "Type instantiation is excessively deep and possibly infinite"
? `${Key}.*` | (ResolveUseSettings<T[Key]> extends Record<string, string> ? `${Key}.${ResolveUseSettings<T[Key]>[keyof T[Key]]}` : never)
: Key
: never;
? T[Key] extends Record<string, unknown>
// @ts-expect-error "Type instantiation is excessively deep and possibly infinite"
? `${Key}.*` | (ResolveUseSettings<T[Key]> extends Record<string, string> ? `${Key}.${ResolveUseSettings<T[Key]>[keyof T[Key]]}` : never)
: Key
: never;
};

View file

@ -181,26 +181,26 @@ function UpdateLogCard({
{log.newSettings &&
getNewSettingsSize(log.newSettings) > 0 && (
<div className="vc-changelog-log-plugins">
<Heading className={Margins.bottom8}>
{t("vencord.settings.changelog.updateCard.newSettings")}
</Heading>
<div className="vc-changelog-new-plugins-list">
{getNewSettingsEntries(log.newSettings).map(
([pluginName, settings]) =>
settings.map(setting => (
<span
key={`${pluginName}-${setting}`}
className="vc-changelog-new-plugin-tag"
title={t("vencord.settings.changelog.updateCard.newSettingInPlugin", { pluginName: pluginName })}
>
{pluginName}.{setting}
</span>
)),
)}
</div>
<div className="vc-changelog-log-plugins">
<Heading className={Margins.bottom8}>
{t("vencord.settings.changelog.updateCard.newSettings")}
</Heading>
<div className="vc-changelog-new-plugins-list">
{getNewSettingsEntries(log.newSettings).map(
([pluginName, settings]) =>
settings.map(setting => (
<span
key={`${pluginName}-${setting}`}
className="vc-changelog-new-plugin-tag"
title={t("vencord.settings.changelog.updateCard.newSettingInPlugin", { pluginName: pluginName })}
>
{pluginName}.{setting}
</span>
)),
)}
</div>
)}
</div>
)}
{log.commits.length > 0 && (
<div className="vc-changelog-log-commits">

View file

@ -79,22 +79,22 @@ function ContributorModal({ user }: { user: User; }) {
<HeadingPrimary className={cl("name")}>{user.username}</HeadingPrimary>
</div>
{plugins.length ? (
<Paragraph>
<Translate
i18nKey="vencord.settings.plugins.contributorModal.contributorInfo.plugins"
variables={{ count: plugins.length }}>
This person has {ContributedHyperLink} to some plugins!
</Translate>
</Paragraph>
) : (
<Paragraph >
<Translate i18nKey="vencord.settings.plugins.contributorModal.contributorInfo.noPlugins">
This person has not made any plugins. They likely {ContributedHyperLink}
to Equicord in other ways!
</Translate>
</Paragraph >
)}
{plugins.length ? (
<Paragraph>
<Translate
i18nKey="vencord.settings.plugins.contributorModal.contributorInfo.plugins"
variables={{ count: plugins.length }}>
This person has {ContributedHyperLink} to some plugins!
</Translate>
</Paragraph>
) : (
<Paragraph >
<Translate i18nKey="vencord.settings.plugins.contributorModal.contributorInfo.noPlugins">
This person has not made any plugins. They likely {ContributedHyperLink}
to Equicord in other ways!
</Translate>
</Paragraph >
)}
{!!plugins.length && (
<div className={cl("plugins")}>

View file

@ -471,16 +471,16 @@ export default function ChannelTab(props: ChannelTabsProps & { index: number; })
const hasActiveQuests = activeQuestIntervals.size > 0;
return <div
className={cl("tab", {
"tab-compact": compact,
"tab-selected": isTabSelected(id),
"tab-entering": isEntering,
"tab-closing": isClosing,
"tab-dragging": isDragging,
"tab-drop-target": isDropTarget,
"tab-nitro": channelId === "__nitro__",
"tab-quests-active": channelId === "__quests__" && hasActiveQuests,
wider: settings.store.widerTabsAndBookmarks
})}
"tab-compact": compact,
"tab-selected": isTabSelected(id),
"tab-entering": isEntering,
"tab-closing": isClosing,
"tab-dragging": isDragging,
"tab-drop-target": isDropTarget,
"tab-nitro": channelId === "__nitro__",
"tab-quests-active": channelId === "__quests__" && hasActiveQuests,
wider: settings.store.widerTabsAndBookmarks
})}
key={index}
ref={ref}
onMouseEnter={() => setIsHovered(true)}

View file

@ -116,9 +116,9 @@ export function makeContextItem(a: folderProp) {
</ModalRoot>
);
},
{
modalKey: "custom-folder-icon"
});
{
modalKey: "custom-folder-icon"
});
}} />
);
}

View file

@ -45,7 +45,7 @@ export function buildPluginMenuEntries(includeEmpty = false) {
const sortedPlugins = useMemo(() =>
Object.values(plugins).sort((a, b) => a.name.localeCompare(b.name)),
[]
[]
);
const candidates = useMemo(() =>
@ -57,7 +57,7 @@ export function buildPluginMenuEntries(includeEmpty = false) {
const name = p.name.toLowerCase();
return name.includes(lowerSearch);
}),
[lowerSearch]
[lowerSearch]
);
return (

View file

@ -79,7 +79,7 @@ function IconsTab() {
const filteredIcons = useMemo(() =>
Object.entries(icons).filter(([name, Icon]) => searchMatch(search, name, Icon, searchByFunction)),
[icons, search, searchByFunction]
[icons, search, searchByFunction]
);
const iconsToLoad = 120;

View file

@ -34,7 +34,7 @@ const noDrag = {
};
const StickerPackMetadata = ({ meta, hoveredStickerPackId, setHoveredStickerPackId, refreshStickerPackMetas }:
{ meta: StickerPackMeta, [key: string]: any; }
{ meta: StickerPackMeta, [key: string]: any; }
) => {
return (
<div className="sticker-pack"

View file

@ -167,14 +167,14 @@ function GensokyoRadioSettings() {
<>
<SettingsSection name="" description="Discord rich presence for Gensokyo Radio. Just enable it and listen!" />
<SettingsSection name="Refresh Interval" description="Refresh interval in seconds.">
<Slider
markers={[1, 2, 2.5, 3, 5, 10, 15]}
initialValue={value}
onValueChange={v => { setValue(v); settings.store.gr_refreshInterval = v; }}
onValueRender={v => `${v}s`}
stickToMarkers
/>
</SettingsSection>
<Slider
markers={[1, 2, 2.5, 3, 5, 10, 15]}
initialValue={value}
onValueChange={v => { setValue(v); settings.store.gr_refreshInterval = v; }}
onValueRender={v => `${v}s`}
stickToMarkers
/>
</SettingsSection>
</>
);
}

View file

@ -44,11 +44,11 @@ async function fetchMediaData(): Promise<JfMediaData | null> {
const contentType = res.headers.get("content-type") ?? "";
if (!contentType.includes("application/json")) {
if (!hasShownError) {
logger.error("Jellyfin returned non-JSON response. Check your server URL and API key.");
showToast("Jellyfin returned an invalid response. Your API key may be wrong.", "failure", { duration: 15000 });
hasShownError = true;
}
if (!hasShownError) {
logger.error("Jellyfin returned non-JSON response. Check your server URL and API key.");
showToast("Jellyfin returned an invalid response. Your API key may be wrong.", "failure", { duration: 15000 });
hasShownError = true;
}
return null;
}

View file

@ -251,61 +251,61 @@ function UserPluginsTab() {
{Object.keys(
pluginsWithUpdates,
).includes(plugin.directory!) && (
<Button
size="small"
onClick={async () => {
try {
await Native.updatePlugin(
<Button
size="small"
onClick={async () => {
try {
await Native.updatePlugin(
plugin.directory!,
);
const oldPWU =
userpluginInstaller.pluginsWithUpdates.value()
.plugins;
oldPWU.splice(
oldPWU.indexOf(
plugin.directory!,
);
const oldPWU =
userpluginInstaller.pluginsWithUpdates.value()
.plugins;
oldPWU.splice(
oldPWU.indexOf(
plugin.directory!,
),
1,
);
userpluginInstaller.pluginsWithUpdates.value(
{
finished: true,
plugins: oldPWU,
},
);
Alerts.show({
title: "Done!",
body: `${plugin.name} has been updated. A ${plugin.usesNative ? "restart" : "refresh"} is needed to apply the update.`,
confirmText:
),
1,
);
userpluginInstaller.pluginsWithUpdates.value(
{
finished: true,
plugins: oldPWU,
},
);
Alerts.show({
title: "Done!",
body: `${plugin.name} has been updated. A ${plugin.usesNative ? "restart" : "refresh"} is needed to apply the update.`,
confirmText:
plugin.usesNative
? "Restart"
: "Refresh",
cancelText: "Later",
onConfirm() {
plugin.usesNative
? relaunch()
: window.location.reload();
},
});
} catch (e: any) {
if (
e
.toString()
.includes(
"silentStop",
)
)
return;
Alerts.show({
title: "Update error",
body: e.toString(),
});
}
}}
>
Update
</Button>
)}
cancelText: "Later",
onConfirm() {
plugin.usesNative
? relaunch()
: window.location.reload();
},
});
} catch (e: any) {
if (
e
.toString()
.includes(
"silentStop",
)
)
return;
Alerts.show({
title: "Update error",
body: e.toString(),
});
}
}}
>
Update
</Button>
)}
<Button
variant="secondary"
size="small"

View file

@ -33,21 +33,21 @@ export default function UserpluginInstallButton({ props }: any) {
<Button style={{
marginTop: "5px"
}}
variant={installed ? "secondary" : "primary"}
onClick={async () => {
if (installed) return void OpenSettingsModule.openUserSettings("vencord_userplugins_panel");
try {
const { name, native } = JSON.parse(await Native.initPluginInstall(gitLink[0], gitLink[[1, 4][idpl]], gitLink[[2, 5][idpl]], gitLink[[3, 6][idpl]]));
showInstallFinishedAlert(name, native);
}
catch (e: any) {
if (e.toString().includes("silentStop")) return;
Alerts.show({
title: "Install error",
body: e.toString()
});
}
}}>
variant={installed ? "secondary" : "primary"}
onClick={async () => {
if (installed) return void OpenSettingsModule.openUserSettings("vencord_userplugins_panel");
try {
const { name, native } = JSON.parse(await Native.initPluginInstall(gitLink[0], gitLink[[1, 4][idpl]], gitLink[[2, 5][idpl]], gitLink[[3, 6][idpl]]));
showInstallFinishedAlert(name, native);
}
catch (e: any) {
if (e.toString().includes("silentStop")) return;
Alerts.show({
title: "Install error",
body: e.toString()
});
}
}}>
{installed ? "Manage plugins" : "Install plugin"}
</Button>
</div>

View file

@ -273,8 +273,8 @@ export default definePlugin({
const hide = !this.keepSuppressedMessage(message.author.id) || (
message.interaction && !this.keepSuppressedMessage((message.interaction as any).user.id)
) || (
prefixCMDReference && !this.keepSuppressedMessage(prefixCMDReference.author.id)
);
prefixCMDReference && !this.keepSuppressedMessage(prefixCMDReference.author.id)
);
return { suppressed, hide };
} catch (e) {
new Logger("NoBlockedMessages").error("Failed to check if message is blocked or ignored:", e);

View file

@ -1,19 +1,7 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
* Vencord, a Discord client mod
* Copyright (c) 2026 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Auth, getToken } from "@plugins/reviewDB/auth";

View file

@ -20,8 +20,8 @@ import { definePluginSettings } from "@api/Settings";
import { disableStyle, enableStyle } from "@api/Styles";
import { parseUrl } from "@utils/misc";
import { wordsFromPascal, wordsToTitle } from "@utils/text";
import { OptionType } from "@utils/types";
import { t } from "@utils/translation";
import { OptionType } from "@utils/types";
import { shiki } from "./api/shiki";
import { themes } from "./api/themes";

View file

@ -5,7 +5,7 @@
*/
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { MessageActions, PinActions } from "@webpack/common";
@ -26,7 +26,7 @@ export default definePlugin({
name: "ShowAllMessageButtons",
description: "Always show all message buttons no matter if you are holding the shift key or not.",
tags: ["Chat", "Utility"],
authors: [Devs.Nuckyz],
authors: [Devs.Nuckyz, EquicordDevs.mochienya],
settings,
patches: [

View file

@ -17,8 +17,8 @@
*/
import { definePluginSettings } from "@api/Settings";
import { OptionType } from "@utils/types";
import { t } from "@utils/translation";
import { OptionType } from "@utils/types";
export const enum PronounsFormat {
Lowercase = "LOWERCASE",

View file

@ -12,16 +12,16 @@ export const SYM_GET_RAW_TARGET = Symbol("SettingsStore.getRawTarget");
// Resolves a possibly nested prop in the form of "some.nested.prop" to type of T.some.nested.prop
type ResolvePropDeep<T, P> =
P extends `${infer Pre}.*` ?
Pre extends keyof T
? T[Pre][keyof T[Pre]]
: any
: P extends `${infer Pre}.${infer Suf}`
? Pre extends keyof T
? ResolvePropDeep<T[Pre], Suf>
: any
: P extends keyof T
? T[P]
: any;
Pre extends keyof T
? T[Pre][keyof T[Pre]]
: any
: P extends `${infer Pre}.${infer Suf}`
? Pre extends keyof T
? ResolvePropDeep<T[Pre], Suf>
: any
: P extends keyof T
? T[P]
: any;
interface SettingsStoreOptions {
readOnly?: boolean;

View file

@ -278,7 +278,7 @@ export const enum OptionType {
export type SettingsDefinition = Record<string, PluginSettingDef>;
export type SettingsChecks<D extends SettingsDefinition> = {
[K in keyof D]?: D[K] extends PluginSettingComponentDef ? IsDisabled<DefinedSettings<D>> :
(IsDisabled<DefinedSettings<D>> & IsValid<PluginSettingType<D[K]>, DefinedSettings<D>>);
(IsDisabled<DefinedSettings<D>> & IsValid<PluginSettingType<D[K]>, DefinedSettings<D>>);
};
export type PluginSettingDef =
@ -398,13 +398,13 @@ export interface PluginSettingComponentDef {
/** Maps a `PluginSettingDef` to its value type */
type PluginSettingType<O extends PluginSettingDef> = O extends PluginSettingStringDef ? string :
O extends PluginSettingNumberDef ? number :
O extends PluginSettingBigIntDef ? BigInt :
O extends PluginSettingBooleanDef ? boolean :
O extends PluginSettingSelectDef ? O["options"][number]["value"] :
O extends PluginSettingSliderDef ? number :
O extends PluginSettingComponentDef ? O extends { default: infer Default; } ? Default : any :
O extends PluginSettingCustomDef ? O extends { default: infer Default; } ? Default : any :
never;
O extends PluginSettingBigIntDef ? BigInt :
O extends PluginSettingBooleanDef ? boolean :
O extends PluginSettingSelectDef ? O["options"][number]["value"] :
O extends PluginSettingSliderDef ? number :
O extends PluginSettingComponentDef ? O extends { default: infer Default; } ? Default : any :
O extends PluginSettingCustomDef ? O extends { default: infer Default; } ? Default : any :
never;
type PluginSettingDefaultType<O extends PluginSettingDef> = O extends PluginSettingSelectDef ? (
O["options"] extends { default?: boolean; }[] ? O["options"][number]["value"] : undefined
@ -470,8 +470,8 @@ export type PluginOptionCustom = PluginSettingCustomDef & Pick<PluginSettingComm
export type PluginNative<PluginExports extends Record<string, (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any>> = {
[key in keyof PluginExports]:
PluginExports[key] extends (event: Electron.IpcMainInvokeEvent, ...args: infer Args) => infer Return
? (...args: Args) => Return extends Promise<any> ? Return : Promise<Return>
: never;
? (...args: Args) => Return extends Promise<any> ? Return : Promise<Return>
: never;
};
export type AllOrNothing<T> = T | { [K in keyof T]?: never; };