feat: non-exact settings subscriptions for live recompile
This commit is contained in:
parent
64848b2fbf
commit
51059c29e7
3 changed files with 18 additions and 9 deletions
|
@ -117,7 +117,7 @@ const saveSettingsOnFrequentAction = debounce(async () => {
|
||||||
}
|
}
|
||||||
}, 60_000);
|
}, 60_000);
|
||||||
|
|
||||||
type SubscriptionCallback = ((newValue: any, path: string) => void) & { _paths?: Array<string>; };
|
type SubscriptionCallback = ((newValue: any, path: string) => void) & { _paths?: Array<string>; _exact?: boolean; };
|
||||||
const subscriptions = new Set<SubscriptionCallback>();
|
const subscriptions = new Set<SubscriptionCallback>();
|
||||||
|
|
||||||
const proxyCache = {} as Record<string, any>;
|
const proxyCache = {} as Record<string, any>;
|
||||||
|
@ -174,7 +174,12 @@ function makeProxy(settings: any, root = settings, path = ""): Settings {
|
||||||
const setPath = `${path}${path && "."}${p}`;
|
const setPath = `${path}${path && "."}${p}`;
|
||||||
delete proxyCache[setPath];
|
delete proxyCache[setPath];
|
||||||
for (const subscription of subscriptions) {
|
for (const subscription of subscriptions) {
|
||||||
if (!subscription._paths || subscription._paths.includes(setPath)) {
|
if (
|
||||||
|
!subscription._paths ||
|
||||||
|
(subscription._exact
|
||||||
|
? subscription._paths.includes(setPath)
|
||||||
|
: subscription._paths.some(p => setPath.startsWith(p)))
|
||||||
|
) {
|
||||||
subscription(v, setPath);
|
subscription(v, setPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,11 +217,14 @@ export const Settings = makeProxy(settings);
|
||||||
* @returns Settings
|
* @returns Settings
|
||||||
*/
|
*/
|
||||||
// TODO: Representing paths as essentially "string[].join('.')" wont allow dots in paths, change to "paths?: string[][]" later
|
// TODO: Representing paths as essentially "string[].join('.')" wont allow dots in paths, change to "paths?: string[][]" later
|
||||||
export function useSettings(paths?: UseSettings<Settings>[]) {
|
export function useSettings(paths?: UseSettings<Settings>[], exact = true) {
|
||||||
const [, forceUpdate] = React.useReducer(() => ({}), {});
|
const [, forceUpdate] = React.useReducer(() => ({}), {});
|
||||||
|
|
||||||
const onUpdate: SubscriptionCallback = paths
|
const onUpdate: SubscriptionCallback = paths
|
||||||
? (value, path) => paths.includes(path as UseSettings<Settings>) && forceUpdate()
|
? (value, path) =>
|
||||||
|
(exact
|
||||||
|
? paths.includes(path as UseSettings<Settings>)
|
||||||
|
: paths.some(p => path.startsWith(p))) && forceUpdate()
|
||||||
: forceUpdate;
|
: forceUpdate;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -242,10 +250,11 @@ type ResolvePropDeep<T, P> = P extends "" ? T :
|
||||||
* @example addSettingsListener("", (newValue, path) => console.log(`${path} is now ${newValue}`))
|
* @example addSettingsListener("", (newValue, path) => console.log(`${path} is now ${newValue}`))
|
||||||
* addSettingsListener("plugins.Unindent.enabled", v => console.log("Unindent is now", v ? "enabled" : "disabled"))
|
* addSettingsListener("plugins.Unindent.enabled", v => console.log("Unindent is now", v ? "enabled" : "disabled"))
|
||||||
*/
|
*/
|
||||||
export function addSettingsListener<Path extends keyof Settings>(path: Path, onUpdate: (newValue: Settings[Path], path: Path) => void): void;
|
export function addSettingsListener<Path extends keyof Settings>(path: Path, onUpdate: (newValue: Settings[Path], path: Path) => void, exact?: boolean): void;
|
||||||
export function addSettingsListener<Path extends string>(path: Path, onUpdate: (newValue: Path extends "" ? any : ResolvePropDeep<Settings, Path>, path: Path extends "" ? string : Path) => void): void;
|
export function addSettingsListener<Path extends string>(path: Path, onUpdate: (newValue: Path extends "" ? any : ResolvePropDeep<Settings, Path>, path: Path extends "" ? string : Path) => void, exact?: boolean): void;
|
||||||
export function addSettingsListener(path: string, onUpdate: (newValue: any, path: string) => void) {
|
export function addSettingsListener(path: string, onUpdate: (newValue: any, path: string) => void, exact = true) {
|
||||||
((onUpdate as SubscriptionCallback)._paths ??= []).push(path);
|
((onUpdate as SubscriptionCallback)._paths ??= []).push(path);
|
||||||
|
(onUpdate as SubscriptionCallback)._exact = exact;
|
||||||
subscriptions.add(onUpdate);
|
subscriptions.add(onUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ interface UserCSSSettingsModalProps {
|
||||||
|
|
||||||
function UserCSSSettingsModal({ modalProps, theme }: UserCSSSettingsModalProps) {
|
function UserCSSSettingsModal({ modalProps, theme }: UserCSSSettingsModalProps) {
|
||||||
// @ts-expect-error UseSettings<> can't determine this is a valid key
|
// @ts-expect-error UseSettings<> can't determine this is a valid key
|
||||||
const themeSettings = useSettings(["userCssVars"]).userCssVars[theme.id];
|
const themeSettings = useSettings(["userCssVars"], false).userCssVars[theme.id];
|
||||||
|
|
||||||
const controls: ReactNode[] = [];
|
const controls: ReactNode[] = [];
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
addSettingsListener("themeLinks", initThemes);
|
addSettingsListener("themeLinks", initThemes);
|
||||||
addSettingsListener("enabledThemes", initThemes);
|
addSettingsListener("enabledThemes", initThemes);
|
||||||
addSettingsListener("userCssVars", initThemes);
|
addSettingsListener("userCssVars", initThemes, false);
|
||||||
|
|
||||||
if (!IS_WEB)
|
if (!IS_WEB)
|
||||||
VencordNative.quickCss.addThemeChangeListener(initThemes);
|
VencordNative.quickCss.addThemeChangeListener(initThemes);
|
||||||
|
|
Loading…
Reference in a new issue