[skip ci] docs docs docs
This commit is contained in:
parent
c2c6c9fccb
commit
a85ec594a7
7 changed files with 63 additions and 33 deletions
|
@ -302,7 +302,7 @@ export default ErrorBoundary.wrap(function Settings() {
|
||||||
<PluginCard
|
<PluginCard
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onRestartNeeded={name => changes.add(name)}
|
onRestartNeeded={name => changes.handleChange(name)}
|
||||||
disabled={plugin.required || !!dependency}
|
disabled={plugin.required || !!dependency}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -17,11 +17,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSettings } from "../api/settings";
|
import { useSettings } from "../api/settings";
|
||||||
import { ChangeList } from "../utils/ChangeList";
|
|
||||||
import IpcEvents from "../utils/IpcEvents";
|
import IpcEvents from "../utils/IpcEvents";
|
||||||
import { useAwaiter } from "../utils/misc";
|
import { useAwaiter } from "../utils/misc";
|
||||||
import { downloadSettingsBackup, uploadSettingsBackup } from "../utils/settingsSync";
|
import { downloadSettingsBackup, uploadSettingsBackup } from "../utils/settingsSync";
|
||||||
import { Alerts, Button, Card, Forms, Margins, Parser, React, Switch } from "../webpack/common";
|
import { Button, Card, Forms, Margins, React, Switch } from "../webpack/common";
|
||||||
import DonateButton from "./DonateButton";
|
import DonateButton from "./DonateButton";
|
||||||
import ErrorBoundary from "./ErrorBoundary";
|
import ErrorBoundary from "./ErrorBoundary";
|
||||||
import { Flex } from "./Flex";
|
import { Flex } from "./Flex";
|
||||||
|
@ -30,27 +29,6 @@ import { handleComponentFailed } from "./handleComponentFailed";
|
||||||
export default ErrorBoundary.wrap(function Settings() {
|
export default ErrorBoundary.wrap(function Settings() {
|
||||||
const [settingsDir, , settingsDirPending] = useAwaiter(() => VencordNative.ipc.invoke<string>(IpcEvents.GET_SETTINGS_DIR), "Loading...");
|
const [settingsDir, , settingsDirPending] = useAwaiter(() => VencordNative.ipc.invoke<string>(IpcEvents.GET_SETTINGS_DIR), "Loading...");
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const changes = React.useMemo(() => new ChangeList<string>(), []);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
return () => void (changes.hasChanges && Alerts.show({
|
|
||||||
title: "Restart required",
|
|
||||||
body: (
|
|
||||||
<>
|
|
||||||
<p>The following plugins require a restart:</p>
|
|
||||||
<div>{changes.map((s, i) => (
|
|
||||||
<>
|
|
||||||
{i > 0 && ", "}
|
|
||||||
{Parser.parse("`" + s + "`")}
|
|
||||||
</>
|
|
||||||
))}</div>
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
confirmText: "Restart now",
|
|
||||||
cancelText: "Later!",
|
|
||||||
onConfirm: () => location.reload()
|
|
||||||
}));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection tag="h1" title="Vencord">
|
<Forms.FormSection tag="h1" title="Vencord">
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
import { Promisable } from "type-fest";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A queue that can be used to run tasks consecutively.
|
||||||
|
* Highly recommended for things like fetching data from Discord
|
||||||
|
*/
|
||||||
export class Queue {
|
export class Queue {
|
||||||
/**
|
/**
|
||||||
* @param maxSize The maximum amount of functions that can be queued at once.
|
* @param maxSize The maximum amount of functions that can be queued at once.
|
||||||
|
@ -25,7 +29,7 @@ export class Queue {
|
||||||
*/
|
*/
|
||||||
constructor(public maxSize = Infinity) { }
|
constructor(public maxSize = Infinity) { }
|
||||||
|
|
||||||
queue = [] as Array<() => Promisable<unknown>>;
|
private queue = [] as Array<() => Promisable<unknown>>;
|
||||||
|
|
||||||
private promise?: Promise<any>;
|
private promise?: Promise<any>;
|
||||||
|
|
||||||
|
@ -34,7 +38,7 @@ export class Queue {
|
||||||
if (func)
|
if (func)
|
||||||
this.promise = Promise.resolve()
|
this.promise = Promise.resolve()
|
||||||
.then(func)
|
.then(func)
|
||||||
.then(() => this.next());
|
.finally(() => this.next());
|
||||||
else
|
else
|
||||||
this.promise = undefined;
|
this.promise = undefined;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +48,11 @@ export class Queue {
|
||||||
this.next();
|
this.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a task at the end of the queue. This task will be executed after all other tasks
|
||||||
|
* If the queue exceeds the specified maxSize, the first task in queue will be removed.
|
||||||
|
* @param func Task
|
||||||
|
*/
|
||||||
push<T>(func: () => Promisable<T>) {
|
push<T>(func: () => Promisable<T>) {
|
||||||
if (this.size >= this.maxSize)
|
if (this.size >= this.maxSize)
|
||||||
this.queue.shift();
|
this.queue.shift();
|
||||||
|
@ -52,6 +61,11 @@ export class Queue {
|
||||||
this.run();
|
this.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepend a task at the beginning of the queue. This task will be executed next
|
||||||
|
* If the queue exceeds the specified maxSize, the last task in queue will be removed.
|
||||||
|
* @param func Task
|
||||||
|
*/
|
||||||
unshift<T>(func: () => Promisable<T>) {
|
unshift<T>(func: () => Promisable<T>) {
|
||||||
if (this.size >= this.maxSize)
|
if (this.size >= this.maxSize)
|
||||||
this.queue.pop();
|
this.queue.pop();
|
||||||
|
@ -60,6 +74,9 @@ export class Queue {
|
||||||
this.run();
|
this.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of tasks in the queue
|
||||||
|
*/
|
||||||
get size() {
|
get size() {
|
||||||
return this.queue.length;
|
return this.queue.length;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new function that will call the wrapped function
|
||||||
|
* after the specified delay. If the function is called again
|
||||||
|
* within the delay, the timer will be reset.
|
||||||
|
* @param func The function to wrap
|
||||||
|
* @param delay The delay in milliseconds
|
||||||
|
*/
|
||||||
export function debounce<T extends Function>(func: T, delay = 300): T {
|
export function debounce<T extends Function>(func: T, delay = 300): T {
|
||||||
let timeout: NodeJS.Timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
return function (...args: any[]) {
|
return function (...args: any[]) {
|
||||||
|
|
|
@ -70,6 +70,9 @@ export function useAwaiter<T>(factory: () => Promise<T>, fallbackValue: T | null
|
||||||
return [state.value, state.error, state.pending, () => setSignal(signal + 1)];
|
return [state.value, state.error, state.pending, () => setSignal(signal + 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function that can be used to force rerender react components
|
||||||
|
*/
|
||||||
export function useForceUpdater() {
|
export function useForceUpdater() {
|
||||||
const [, set] = React.useState(0);
|
const [, set] = React.useState(0);
|
||||||
return () => set(s => s + 1);
|
return () => set(s => s + 1);
|
||||||
|
@ -144,6 +147,9 @@ export function classes(...classes: string[]) {
|
||||||
return classes.join(" ");
|
return classes.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves after the specified amount of time
|
||||||
|
*/
|
||||||
export function sleep(ms: number): Promise<void> {
|
export function sleep(ms: number): Promise<void> {
|
||||||
return new Promise(r => setTimeout(r, ms));
|
return new Promise(r => setTimeout(r, ms));
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,14 +76,26 @@ const ModalAPI = mapMangledModuleLazy("onCloseRequest:null!=", {
|
||||||
openModalLazy: m => m?.length === 1 && filters.byCode(".apply(this,arguments)")(m),
|
openModalLazy: m => m?.length === 1 && filters.byCode(".apply(this,arguments)")(m),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the render promise to resolve, then open a modal with it.
|
||||||
|
* This is equivalent to render().then(openModal)
|
||||||
|
* You should use the Modal components exported by this file
|
||||||
|
*/
|
||||||
export function openModalLazy(render: () => Promise<RenderFunction>, options?: ModalOptions & { contextKey?: string; }): Promise<string> {
|
export function openModalLazy(render: () => Promise<RenderFunction>, options?: ModalOptions & { contextKey?: string; }): Promise<string> {
|
||||||
return ModalAPI.openModalLazy(render, options);
|
return ModalAPI.openModalLazy(render, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a Modal with the given render function.
|
||||||
|
* You should use the Modal components exported by this file
|
||||||
|
*/
|
||||||
export function openModal(render: RenderFunction, options?: ModalOptions, contextKey?: string): string {
|
export function openModal(render: RenderFunction, options?: ModalOptions, contextKey?: string): string {
|
||||||
return ModalAPI.openModal(render, options, contextKey);
|
return ModalAPI.openModal(render, options, contextKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a modal by its key
|
||||||
|
*/
|
||||||
export function closeModal(modalKey: string, contextKey?: string): void {
|
export function closeModal(modalKey: string, contextKey?: string): void {
|
||||||
return ModalAPI.closeModal(modalKey, contextKey);
|
return ModalAPI.closeModal(modalKey, contextKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,6 @@ export const filters = {
|
||||||
? m => m[props[0]] !== void 0
|
? m => m[props[0]] !== void 0
|
||||||
: m => props.every(p => m[p] !== void 0),
|
: m => props.every(p => m[p] !== void 0),
|
||||||
|
|
||||||
byDisplayName: (deezNuts: string): FilterFn => m => m.default?.displayName === deezNuts,
|
|
||||||
|
|
||||||
byCode: (...code: string[]): FilterFn => m => {
|
byCode: (...code: string[]): FilterFn => m => {
|
||||||
if (typeof m !== "function") return false;
|
if (typeof m !== "function") return false;
|
||||||
const s = Function.prototype.toString.call(m);
|
const s = Function.prototype.toString.call(m);
|
||||||
|
@ -75,6 +73,9 @@ if (IS_DEV && !IS_WEB) {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first module that matches the filter
|
||||||
|
*/
|
||||||
export const find = traceFunction("find", function find(filter: FilterFn, getDefault = true, isWaitFor = false) {
|
export const find = traceFunction("find", function find(filter: FilterFn, getDefault = true, isWaitFor = false) {
|
||||||
if (typeof filter !== "function")
|
if (typeof filter !== "function")
|
||||||
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
throw new Error("Invalid filter. Expected a function got " + typeof filter);
|
||||||
|
@ -283,22 +284,31 @@ export function mapMangledModuleLazy<S extends string>(code: string, mappers: Re
|
||||||
return proxyLazy(() => mapMangledModule(code, mappers));
|
return proxyLazy(() => mapMangledModule(code, mappers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first module that has the specified properties
|
||||||
|
*/
|
||||||
export function findByProps(...props: string[]) {
|
export function findByProps(...props: string[]) {
|
||||||
return find(filters.byProps(...props));
|
return find(filters.byProps(...props));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all modules that have the specified properties
|
||||||
|
*/
|
||||||
export function findAllByProps(...props: string[]) {
|
export function findAllByProps(...props: string[]) {
|
||||||
return findAll(filters.byProps(...props));
|
return findAll(filters.byProps(...props));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a function by its code
|
||||||
|
*/
|
||||||
export function findByCode(...code: string[]) {
|
export function findByCode(...code: string[]) {
|
||||||
return find(filters.byCode(...code));
|
return find(filters.byCode(...code));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findByDisplayName(deezNuts: string) {
|
/**
|
||||||
return find(filters.byDisplayName(deezNuts));
|
* Wait for a module that matches the provided filter to be registered,
|
||||||
}
|
* then call the callback with the module as the first argument
|
||||||
|
*/
|
||||||
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn) {
|
export function waitFor(filter: string | string[] | FilterFn, callback: CallbackFn) {
|
||||||
if (typeof filter === "string")
|
if (typeof filter === "string")
|
||||||
filter = filters.byProps(filter);
|
filter = filters.byProps(filter);
|
||||||
|
|
Loading…
Reference in a new issue