Add QuickCss toggle; add settings listener api

This commit is contained in:
Vendicated 2022-09-03 17:49:16 +02:00
parent 8a8c6a4b52
commit 113f47ca7f
No known key found for this signature in database
GPG key ID: EC781ADFB93EFFA3
4 changed files with 56 additions and 14 deletions

View file

@ -1,6 +1,7 @@
export * as Plugins from "./plugins"; export * as Plugins from "./plugins";
export * as Webpack from "./webpack"; export * as Webpack from "./webpack";
export * as Api from "./api"; export * as Api from "./api";
export { Settings } from "./api/settings";
import "./utils/patchWebpack"; import "./utils/patchWebpack";
import "./utils/quickCss"; import "./utils/quickCss";

View file

@ -5,6 +5,7 @@ import { mergeDefaults } from '../utils/misc';
interface Settings { interface Settings {
unsafeRequire: boolean; unsafeRequire: boolean;
useQuickCss: boolean;
plugins: { plugins: {
[plugin: string]: { [plugin: string]: {
enabled: boolean; enabled: boolean;
@ -15,8 +16,9 @@ interface Settings {
const DefaultSettings: Settings = { const DefaultSettings: Settings = {
unsafeRequire: false, unsafeRequire: false,
useQuickCss: true,
plugins: {} plugins: {}
}; } as any;
for (const plugin in plugins) { for (const plugin in plugins) {
DefaultSettings.plugins[plugin] = { DefaultSettings.plugins[plugin] = {
@ -35,21 +37,26 @@ try {
var settings = mergeDefaults({} as Settings, DefaultSettings); var settings = mergeDefaults({} as Settings, DefaultSettings);
} }
const subscriptions = new Set<() => void>(); type SubscriptionCallback = ((newValue: any) => void) & { _path?: string; };
const subscriptions = new Set<SubscriptionCallback>();
function makeProxy(settings: Settings, root = settings): Settings { function makeProxy(settings: Settings, root = settings, path = ""): Settings {
return new Proxy(settings, { return new Proxy(settings, {
get(target, p) { get(target, p: string) {
const v = target[p]; const v = target[p];
if (typeof v === "object" && !Array.isArray(v)) return makeProxy(v, root); if (typeof v === "object" && !Array.isArray(v))
return makeProxy(v, root, `${path}${path && "."}${p}`);
return v; return v;
}, },
set(target, p, v) { set(target, p: string, v) {
if (target[p] === v) return true; if (target[p] === v) return true;
target[p] = v; target[p] = v;
const setPath = `${path}${path && "."}${p}`;
for (const subscription of subscriptions) { for (const subscription of subscriptions) {
subscription(); if (!subscription._path || subscription._path === setPath) {
subscription(v);
}
} }
VencordNative.ipc.invoke(IpcEvents.SET_SETTINGS, JSON.stringify(root, null, 4)); VencordNative.ipc.invoke(IpcEvents.SET_SETTINGS, JSON.stringify(root, null, 4));
return true; return true;
@ -78,4 +85,16 @@ export function useSettings() {
}, []); }, []);
return Settings; return Settings;
}
// 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 "" ? T :
P extends `${infer Pre}.${infer Suf}` ?
Pre extends keyof T ? ResolvePropDeep<T[Pre], Suf> : never : P extends keyof T ? T[P] : never;
export function addSettingsListener<Path extends keyof Settings>(path: Path, onUpdate: (newValue: Settings[Path]) => void): void;
export function addSettingsListener<Path extends string>(path: Path, onUpdate: (newValue: ResolvePropDeep<Settings, Path>) => void): void;
export function addSettingsListener(path: string, onUpdate: (newValue: any) => void) {
(onUpdate as SubscriptionCallback)._path = path;
subscriptions.add(onUpdate);
} }

View file

@ -26,6 +26,8 @@ export default ErrorBoundary.wrap(function Settings(props) {
return o; return o;
}, []); }, []);
const sortedPlugins = React.useMemo(() => Object.values(Plugins).sort((a, b) => a.name.localeCompare(b.name)), []);
return ( return (
<Forms.FormSection tag="h1" title="Vencord"> <Forms.FormSection tag="h1" title="Vencord">
<Forms.FormText>SettingsDir: {settingsDir}</Forms.FormText> <Forms.FormText>SettingsDir: {settingsDir}</Forms.FormText>
@ -50,16 +52,23 @@ export default ErrorBoundary.wrap(function Settings(props) {
</Flex.Child> </Flex.Child>
</Flex> </Flex>
<Forms.FormTitle tag="h5">Settings</Forms.FormTitle> <Forms.FormTitle tag="h5">Settings</Forms.FormTitle>
<Switch
value={settings.useQuickCss}
onChange={v => settings.useQuickCss = v}
note="Enable QuickCss"
>
Use QuickCss
</Switch>
<Switch <Switch
value={settings.unsafeRequire} value={settings.unsafeRequire}
onChange={v => settings.unsafeRequire = v} onChange={v => settings.unsafeRequire = v}
note="Enables VencordNative.require. Useful for testing, very bad for security. Leave this off unless you need it." note="Enables VencordNative.require. Useful for testing, very bad for security. Leave this off unless you need it."
> >
Enable Ensafe Require Enable Unsafe Require
</Switch> </Switch>
<Forms.FormDivider /> <Forms.FormDivider />
<Forms.FormTitle tag="h5">Plugins</Forms.FormTitle> <Forms.FormTitle tag="h5">Plugins</Forms.FormTitle>
{Object.values(Plugins).map(p => { {sortedPlugins.map(p => {
const enabledDependants = depMap[p.name]?.filter(d => settings.plugins[d].enabled); const enabledDependants = depMap[p.name]?.filter(d => settings.plugins[d].enabled);
const dependency = enabledDependants?.length; const dependency = enabledDependants?.length;

View file

@ -1,8 +1,21 @@
import { addSettingsListener, Settings } from "../api/settings";
import IpcEvents from "./IpcEvents"; import IpcEvents from "./IpcEvents";
document.addEventListener("DOMContentLoaded", async () => { let style: HTMLStyleElement;
const style = document.createElement("style");
document.head.appendChild(style); export async function toggle(isEnabled: boolean) {
VencordNative.ipc.on(IpcEvents.QUICK_CSS_UPDATE, (_, css: string) => style.innerText = css); if (!style) {
style.innerText = await VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS); if (isEnabled) {
style = document.createElement("style");
style.id = "vencord-custom-css";
document.head.appendChild(style);
VencordNative.ipc.on(IpcEvents.QUICK_CSS_UPDATE, (_, css: string) => style.innerText = css);
style.innerText = await VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS);
}
} else style.disabled = !isEnabled;
}
document.addEventListener("DOMContentLoaded", () => {
toggle(Settings.useQuickCss);
addSettingsListener("useQuickCss", toggle);
}); });