diff options
Diffstat (limited to 'src')
24 files changed, 305 insertions, 86 deletions
diff --git a/src/Vencord.ts b/src/Vencord.ts index 464be2d..48e628f 100644 --- a/src/Vencord.ts +++ b/src/Vencord.ts @@ -18,7 +18,6 @@ export * as Api from "./api"; export * as Plugins from "./plugins"; -// eslint-disable-next-line @typescript-eslint/no-restricted-imports export * as Util from "./utils"; export * as QuickCss from "./utils/quickCss"; export * as Updater from "./utils/updater"; diff --git a/src/api/Styles.ts b/src/api/Styles.ts new file mode 100644 index 0000000..6b189ca --- /dev/null +++ b/src/api/Styles.ts @@ -0,0 +1,162 @@ +/* + * 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/>. +*/ + +import type { MapValue } from "type-fest/source/entry"; + +export type Style = MapValue<typeof VencordStyles>; + +export const styleMap = window.VencordStyles ??= new Map(); + +export function requireStyle(name: string) { + const style = styleMap.get(name); + if (!style) throw new Error(`Style "${name}" does not exist`); + return style; +} + +/** + * A style's name can be obtained from importing a stylesheet with `?managed` at the end of the import + * @param name The name of the style + * @returns `false` if the style was already enabled, `true` otherwise + * @example + * import pluginStyle from "./plugin.css?managed"; + * + * // Inside some plugin method like "start()" or "[option].onChange()" + * enableStyle(pluginStyle); + */ +export function enableStyle(name: string) { + const style = requireStyle(name); + + if (style.dom?.isConnected) + return false; + + if (!style.dom) { + style.dom = document.createElement("style"); + style.dom.dataset.vencordName = style.name; + } + compileStyle(style); + + document.head.appendChild(style.dom); + return true; +} + +/** + * @param name The name of the style + * @returns `false` if the style was already disabled, `true` otherwise + * @see {@link enableStyle} for info on getting the name of an imported style + */ +export function disableStyle(name: string) { + const style = requireStyle(name); + if (!style.dom?.isConnected) + return false; + + style.dom.remove(); + style.dom = null; + return true; +} + +/** + * @param name The name of the style + * @returns `true` in most cases, may return `false` in some edge cases + * @see {@link enableStyle} for info on getting the name of an imported style + */ +export const toggleStyle = (name: string) => isStyleEnabled(name) ? disableStyle(name) : enableStyle(name); + +/** + * @param name The name of the style + * @returns Whether the style is enabled + * @see {@link enableStyle} for info on getting the name of an imported style + */ +export const isStyleEnabled = (name: string) => requireStyle(name).dom?.isConnected ?? false; + +/** + * Sets the variables of a style + * ```ts + * // -- plugin.ts -- + * import pluginStyle from "./plugin.css?managed"; + * import { setStyleVars } from "@api/Styles"; + * import { findByPropsLazy } from "@webpack"; + * const classNames = findByPropsLazy("thin", "scrollerBase"); // { thin: "thin-31rlnD scrollerBase-_bVAAt", ... } + * + * // Inside some plugin method like "start()" + * setStyleClassNames(pluginStyle, classNames); + * enableStyle(pluginStyle); + * ``` + * ```scss + * // -- plugin.css -- + * .plugin-root [--thin]::-webkit-scrollbar { ... } + * ``` + * ```scss + * // -- final stylesheet -- + * .plugin-root .thin-31rlnD.scrollerBase-_bVAAt::-webkit-scrollbar { ... } + * ``` + * @param name The name of the style + * @param classNames An object where the keys are the variable names and the values are the variable values + * @param recompile Whether to recompile the style after setting the variables, defaults to `true` + * @see {@link enableStyle} for info on getting the name of an imported style + */ +export const setStyleClassNames = (name: string, classNames: Record<string, string>, recompile = true) => { + const style = requireStyle(name); + style.classNames = classNames; + if (recompile && isStyleEnabled(style.name)) + compileStyle(style); +}; + +/** + * Updates the stylesheet after doing the following to the sourcecode: + * - Interpolate style classnames + * @param style **_Must_ be a style with a DOM element** + * @see {@link setStyleClassNames} for more info on style classnames + */ +export const compileStyle = (style: Style) => { + if (!style.dom) throw new Error("Style has no DOM element"); + + style.dom.textContent = style.source + .replace(/\[--(\w+)\]/g, (match, name) => { + const className = style.classNames[name]; + return className ? classNameToSelector(className) : match; + }); +}; + +/** + * @param name The classname + * @param prefix A prefix to add each class, defaults to `""` + * @return A css selector for the classname + * @example + * classNameToSelector("foo bar") // => ".foo.bar" + */ +export const classNameToSelector = (name: string, prefix = "") => name.split(" ").map(n => `.${prefix}${n}`).join(""); + +type ClassNameFactoryArg = string | string[] | Record<string, unknown>; +/** + * @param prefix The prefix to add to each class, defaults to `""` + * @returns A classname generator function + * @example + * const cl = classNameFactory("plugin-"); + * + * cl("base", ["item", "editable"], { selected: null, disabled: true }) + * // => "plugin-base plugin-item plugin-editable plugin-disabled" + */ +export const classNameFactory = (prefix: string = "") => (...args: ClassNameFactoryArg[]) => { + const classNames = new Set<string>(); + for (const arg of args) { + if (typeof arg === "string") classNames.add(arg); + else if (Array.isArray(arg)) arg.forEach(name => classNames.add(name)); + else if (typeof arg === "object") Object.entries(arg).forEach(([name, value]) => value && classNames.add(name)); + } + return Array.from(classNames, name => prefix + name).join(" "); +}; diff --git a/src/api/index.ts b/src/api/index.ts index 7e981e2..0fef99c 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -26,6 +26,7 @@ import * as $MessageEventsAPI from "./MessageEvents"; import * as $MessagePopover from "./MessagePopover"; import * as $Notices from "./Notices"; import * as $ServerList from "./ServerList"; +import * as $Styles from "./Styles"; /** * An API allowing you to listen to Message Clicks or run your own logic @@ -33,16 +34,16 @@ import * as $ServerList from "./ServerList"; * * If your plugin uses this, you must add MessageEventsAPI to its dependencies */ -const MessageEvents = $MessageEventsAPI; +export const MessageEvents = $MessageEventsAPI; /** * An API allowing you to create custom notices * (snackbars on the top, like the Update prompt) */ -const Notices = $Notices; +export const Notices = $Notices; /** * An API allowing you to register custom commands */ -const Commands = $Commands; +export const Commands = $Commands; /** * A wrapper around IndexedDB. This can store arbitrarily * large data and supports a lot of datatypes (Blob, Map, ...). @@ -57,30 +58,33 @@ const Commands = $Commands; * This is actually just idb-keyval, so if you're familiar with that, you're golden! * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types} */ -const DataStore = $DataStore; +export const DataStore = $DataStore; /** * An API allowing you to add custom components as message accessories */ -const MessageAccessories = $MessageAccessories; +export const MessageAccessories = $MessageAccessories; /** * An API allowing you to add custom buttons in the message popover */ -const MessagePopover = $MessagePopover; +export const MessagePopover = $MessagePopover; /** * An API allowing you to add badges to user profiles */ -const Badges = $Badges; +export const Badges = $Badges; /** * An API allowing you to add custom elements to the server list */ -const ServerList = $ServerList; +export const ServerList = $ServerList; /** * An API allowing you to add components as message accessories */ -const MessageDecorations = $MessageDecorations; +export const MessageDecorations = $MessageDecorations; /** * An API allowing you to add components to member list users, in both DM's and servers */ -const MemberListDecorators = $MemberListDecorators; - -export { Badges, Commands, DataStore, MemberListDecorators, MessageAccessories, MessageDecorations, MessageEvents, MessagePopover, Notices, ServerList }; +export const MemberListDecorators = $MemberListDecorators; +/** + * An API allowing you to dynamically load styles + * a + */ +export const Styles = $Styles; diff --git a/src/components/VencordSettings/index.tsx b/src/components/VencordSettings/index.tsx index b49e4b4..b3a3322 100644 --- a/src/components/VencordSettings/index.tsx +++ b/src/components/VencordSettings/index.tsx @@ -16,22 +16,18 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./settingsStyles.css"; + import ErrorBoundary from "@components/ErrorBoundary"; import { findByCodeLazy } from "@webpack"; import { Forms, Router, Text } from "@webpack/common"; -import cssText from "~fileContent/settingsStyles.css"; - import BackupRestoreTab from "./BackupRestoreTab"; import PluginsTab from "./PluginsTab"; import ThemesTab from "./ThemesTab"; import Updater from "./Updater"; import VencordSettings from "./VencordTab"; -const style = document.createElement("style"); -style.textContent = cssText; -document.head.appendChild(style); - const st = (style: string) => `vcSettings${style}`; const TabBar = findByCodeLazy('[role="tab"][aria-disabled="false"]'); diff --git a/src/globals.d.ts b/src/globals.d.ts index 2e8d444..6c5b437 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -38,6 +38,12 @@ declare global { export var VencordNative: typeof import("./VencordNative").default; export var Vencord: typeof import("./Vencord"); + export var VencordStyles: Map<string, { + name: string; + source: string; + classNames: Record<string, string>; + dom: HTMLStyleElement | null; + }>; export var appSettings: { set(setting: string, v: any): void; }; diff --git a/src/ipcMain/index.ts b/src/ipcMain/index.ts index 86a233c..ae8a96d 100644 --- a/src/ipcMain/index.ts +++ b/src/ipcMain/index.ts @@ -16,6 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./legacy"; import "./updater"; import { debounce } from "@utils/debounce"; diff --git a/src/ipcMain/legacy.ts b/src/ipcMain/legacy.ts new file mode 100644 index 0000000..567ad3d --- /dev/null +++ b/src/ipcMain/legacy.ts @@ -0,0 +1,31 @@ +/* + * 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/>. +*/ + +import IpcEvents from "@utils/IpcEvents"; +import { ipcMain } from "electron"; +import { writeFile } from "fs/promises"; +import { join } from "path"; + +import { get } from "./simpleGet"; + +ipcMain.handleOnce(IpcEvents.DOWNLOAD_VENCORD_CSS, async () => { + const buf = await get("https://github.com/Vendicated/Vencord/releases/download/devbuild/renderer.css"); + await writeFile(join(__dirname, "renderer.css"), buf); + return buf.toString("utf-8"); +}); + diff --git a/src/ipcMain/updater/common.ts b/src/ipcMain/updater/common.ts index 41f08e8..3729c6d 100644 --- a/src/ipcMain/updater/common.ts +++ b/src/ipcMain/updater/common.ts @@ -24,7 +24,7 @@ export async function calculateHashes() { const hashes = {} as Record<string, string>; await Promise.all( - ["patcher.js", "preload.js", "renderer.js"].map(file => new Promise<void>(r => { + ["patcher.js", "preload.js", "renderer.js", "renderer.css"].map(file => new Promise<void>(r => { const fis = createReadStream(join(__dirname, file)); const hash = createHash("sha1", { encoding: "hex" }); fis.once("end", () => { diff --git a/src/ipcMain/updater/http.ts b/src/ipcMain/updater/http.ts index 902d644..3b38144 100644 --- a/src/ipcMain/updater/http.ts +++ b/src/ipcMain/updater/http.ts @@ -69,7 +69,7 @@ async function fetchUpdates() { return false; data.assets.forEach(({ name, browser_download_url }) => { - if (["patcher.js", "preload.js", "renderer.js"].some(s => name.startsWith(s))) { + if (["patcher.js", "preload.js", "renderer.js", "renderer.css"].some(s => name.startsWith(s))) { PendingUpdates.push([name, browser_download_url]); } }); diff --git a/src/modules.d.ts b/src/modules.d.ts index 6901260..c1a1996 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -37,3 +37,9 @@ declare module "~fileContent/*" { const content: string; export default content; } + +declare module "*.css" { } +declare module "*.css?managed" { + const name: string; + export default name; +} diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx index abdb2f2..e650dbb 100644 --- a/src/plugins/messageLogger/index.tsx +++ b/src/plugins/messageLogger/index.tsx @@ -16,6 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./messageLogger.css"; + import { Settings } from "@api/settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; @@ -42,51 +44,14 @@ export default definePlugin({ timestampModule: null as any, moment: null as Function | null, - css: ` - .messagelogger-red-overlay .messageLogger-deleted { - background-color: rgba(240, 71, 71, 0.15); - } - .messagelogger-red-text .messageLogger-deleted div { - color: #f04747; - } - - .messageLogger-deleted [class^="buttons"] { - display: none; - } - - .messageLogger-deleted-attachment { - filter: grayscale(1); - } - - .messageLogger-deleted-attachment:hover { - filter: grayscale(0); - transition: 250ms filter linear; - } - - .theme-dark .messageLogger-edited { - filter: brightness(80%); - } - - .theme-light .messageLogger-edited { - opacity: 0.5; - } - `, - start() { this.moment = findByPropsLazy("relativeTimeRounding", "relativeTimeThreshold"); this.timestampModule = findByPropsLazy("messageLogger_TimestampComponent"); - const style = this.style = document.createElement("style"); - style.textContent = this.css; - style.id = "MessageLogger-css"; - document.head.appendChild(style); - addDeleteStyleClass(); }, stop() { - this.style?.remove(); - document.querySelectorAll(".messageLogger-deleted").forEach(e => e.remove()); document.querySelectorAll(".messageLogger-edited").forEach(e => e.remove()); document.body.classList.remove("messagelogger-red-overlay"); diff --git a/src/plugins/messageLogger/messageLogger.css b/src/plugins/messageLogger/messageLogger.css new file mode 100644 index 0000000..94a3e25 --- /dev/null +++ b/src/plugins/messageLogger/messageLogger.css @@ -0,0 +1,27 @@ +.messagelogger-red-overlay .messageLogger-deleted { + background-color: rgba(240, 71, 71, 0.15); +} +.messagelogger-red-text .messageLogger-deleted div { + color: #f04747; +} + +.messageLogger-deleted [class^="buttons"] { + display: none; +} + +.messageLogger-deleted-attachment { + filter: grayscale(1); +} + +.messageLogger-deleted-attachment:hover { + filter: grayscale(0); + transition: 250ms filter linear; +} + +.theme-dark .messageLogger-edited { + filter: brightness(80%); +} + +.theme-light .messageLogger-edited { + opacity: 0.5; +} diff --git a/src/plugins/shikiCodeblocks/components/Header.tsx b/src/plugins/shikiCodeblocks/components/Header.tsx index c2db386..320dde9 100644 --- a/src/plugins/shikiCodeblocks/components/Header.tsx +++ b/src/plugins/shikiCodeblocks/components/Header.tsx @@ -33,7 +33,7 @@ export function Header({ langName, useDevIcon, shikiLang }: HeaderProps) { <div className={cl("lang")}> {useDevIcon !== DeviconSetting.Disabled && shikiLang?.devicon && ( <i - className={`devicon-${shikiLang.devicon}${useDevIcon === DeviconSetting.Color ? " colored" : ""}`} + className={`${cl("devicon")} devicon-${shikiLang.devicon}${useDevIcon === DeviconSetting.Color ? " colored" : ""}`} /> )} {langName} diff --git a/src/plugins/shikiCodeblocks/components/Highlighter.tsx b/src/plugins/shikiCodeblocks/components/Highlighter.tsx index d26cd81..badb3c8 100644 --- a/src/plugins/shikiCodeblocks/components/Highlighter.tsx +++ b/src/plugins/shikiCodeblocks/components/Highlighter.tsx @@ -90,14 +90,10 @@ export const Highlighter = ({ let langName; if (lang) langName = useHljs ? hljs?.getLanguage?.(lang)?.name : shikiLang?.name; - const preClasses = [cl("root")]; - if (!langName) preClasses.push(cl("plain")); - if (isPreview) preClasses.push(cl("preview")); - return ( <div ref={rootRef} - className={preClasses.join(" ")} + className={cl("root", { plain: !langName, preview: isPreview })} style={{ backgroundColor: useHljs ? themeBase.backgroundColor diff --git a/src/plugins/shikiCodeblocks/devicon.css b/src/plugins/shikiCodeblocks/devicon.css new file mode 100644 index 0000000..f5c4921 --- /dev/null +++ b/src/plugins/shikiCodeblocks/devicon.css @@ -0,0 +1 @@ +@import url('https://cdn.jsdelivr.net/gh/devicons/devicon@v2.10.1/devicon.min.css'); diff --git a/src/plugins/shikiCodeblocks/index.ts b/src/plugins/shikiCodeblocks/index.ts index 58e0048..428a273 100644 --- a/src/plugins/shikiCodeblocks/index.ts +++ b/src/plugins/shikiCodeblocks/index.ts @@ -16,23 +16,25 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./shiki.css"; + +import { disableStyle, enableStyle } from "@api/Styles"; import { Devs } from "@utils/constants"; import { parseUrl } from "@utils/misc"; import { wordsFromPascal, wordsToTitle } from "@utils/text"; import definePlugin, { OptionType } from "@utils/types"; import previewExampleText from "~fileContent/previewExample.tsx"; -import cssText from "~fileContent/shiki.css"; import { Settings } from "../../Vencord"; import { shiki } from "./api/shiki"; import { themes } from "./api/themes"; import { createHighlighter } from "./components/Highlighter"; -import { DeviconSetting, HljsSetting, ShikiSettings, StyleSheets } from "./types"; -import { clearStyles, removeStyle, setStyle } from "./utils/createStyle"; +import deviconStyle from "./devicon.css?managed"; +import { DeviconSetting, HljsSetting, ShikiSettings } from "./types"; +import { clearStyles } from "./utils/createStyle"; const themeNames = Object.keys(themes); -const devIconCss = "@import url('https://cdn.jsdelivr.net/gh/devicons/devicon@v2.10.1/devicon.min.css');"; const getSettings = () => Settings.plugins.ShikiCodeblocks as ShikiSettings; @@ -50,9 +52,8 @@ export default definePlugin({ }, ], start: async () => { - setStyle(cssText, StyleSheets.Main); if (getSettings().useDevIcon !== DeviconSetting.Disabled) - setStyle(devIconCss, StyleSheets.DevIcons); + enableStyle(deviconStyle); await shiki.init(getSettings().customTheme || getSettings().theme); }, @@ -135,8 +136,8 @@ export default definePlugin({ }, ], onChange: (newValue: DeviconSetting) => { - if (newValue === DeviconSetting.Disabled) removeStyle(StyleSheets.DevIcons); - else setStyle(devIconCss, StyleSheets.DevIcons); + if (newValue === DeviconSetting.Disabled) disableStyle(deviconStyle); + else enableStyle(deviconStyle); }, }, bgOpacity: { diff --git a/src/plugins/shikiCodeblocks/shiki.css b/src/plugins/shikiCodeblocks/shiki.css index b871d99..d71b673 100644 --- a/src/plugins/shikiCodeblocks/shiki.css +++ b/src/plugins/shikiCodeblocks/shiki.css @@ -1,6 +1,5 @@ .shiki-container { border: 4px; - /* fallback background */ background-color: var(--background-secondary); } @@ -22,8 +21,7 @@ border: none; } -.shiki-root [class^='devicon-'], -.shiki-root [class*=' devicon-'] { +.shiki-devicon { margin-right: 8px; user-select: none; } diff --git a/src/plugins/shikiCodeblocks/utils/misc.ts b/src/plugins/shikiCodeblocks/utils/misc.ts index 1342ff5..fefe938 100644 --- a/src/plugins/shikiCodeblocks/utils/misc.ts +++ b/src/plugins/shikiCodeblocks/utils/misc.ts @@ -16,13 +16,14 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { classNameFactory } from "@api/Styles"; import { hljs } from "@webpack/common"; import { resolveLang } from "../api/languages"; import { HighlighterProps } from "../components/Highlighter"; import { HljsSetting, ShikiSettings } from "../types"; -export const cl = (className: string) => `shiki-${className}`; +export const cl = classNameFactory("shiki-"); export const shouldUseHljs = ({ lang, diff --git a/src/plugins/spotifyControls/PlayerComponent.tsx b/src/plugins/spotifyControls/PlayerComponent.tsx index af53f59..f6ad08b 100644 --- a/src/plugins/spotifyControls/PlayerComponent.tsx +++ b/src/plugins/spotifyControls/PlayerComponent.tsx @@ -16,6 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import "./spotifyStyles.css"; + import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; import { Link } from "@components/Link"; diff --git a/src/plugins/spotifyControls/SpotifyStore.ts b/src/plugins/spotifyControls/SpotifyStore.ts index 75448dc..641ba1a 100644 --- a/src/plugins/spotifyControls/SpotifyStore.ts +++ b/src/plugins/spotifyControls/SpotifyStore.ts @@ -21,8 +21,6 @@ import { proxyLazy } from "@utils/proxyLazy"; import { findByPropsLazy } from "@webpack"; import { Flux, FluxDispatcher } from "@webpack/common"; -import cssText from "~fileContent/spotifyStyles.css"; - export interface Track { id: string; name: string; @@ -69,11 +67,6 @@ type Repeat = "off" | "track" | "context"; // Don't wanna run before Flux and Dispatcher are ready! export const SpotifyStore = proxyLazy(() => { - // TODO: Move this elsewhere - const style = document.createElement("style"); - style.innerText = cssText; - document.head.appendChild(style); - // For some reason ts hates extends Flux.Store const { Store } = Flux; diff --git a/src/preload.ts b/src/preload.ts index dcf2554..7460081 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -44,6 +44,34 @@ contextBridge.exposeInMainWorld("VencordNative", VencordNative); if (location.protocol !== "data:") { // Discord webFrame.executeJavaScript(readFileSync(join(__dirname, "renderer.js"), "utf-8")); + const rendererCss = join(__dirname, "renderer.css"); + + function insertCss(css: string) { + const style = document.createElement("style"); + style.id = "vencord-css-core"; + style.textContent = css; + + if (document.readyState === "complete") { + document.documentElement.appendChild(style); + } else { + document.addEventListener("DOMContentLoaded", () => document.documentElement.appendChild(style), { + once: true + }); + } + } + + try { + const css = readFileSync(rendererCss, "utf-8"); + insertCss(css); + } catch (err) { + if ((err as NodeJS.ErrnoException)?.code !== "ENOENT") + throw err; + + // hack: the pre update updater does not download this file, so manually download it + // TODO: remove this in a future version + ipcRenderer.invoke(IpcEvents.DOWNLOAD_VENCORD_CSS) + .then(insertCss); + } require(process.env.DISCORD_PRELOAD!); } else { // Monaco Popout diff --git a/src/utils/IpcEvents.ts b/src/utils/IpcEvents.ts index c6696f8..345146b 100644 --- a/src/utils/IpcEvents.ts +++ b/src/utils/IpcEvents.ts @@ -44,5 +44,6 @@ export default strEnum({ UPDATE: "VencordUpdate", BUILD: "VencordBuild", GET_DESKTOP_CAPTURE_SOURCES: "VencordGetDesktopCaptureSources", - OPEN_MONACO_EDITOR: "VencordOpenMonacoEditor" + OPEN_MONACO_EDITOR: "VencordOpenMonacoEditor", + DOWNLOAD_VENCORD_CSS: "VencordDownloadVencordCss" } as const); diff --git a/src/utils/updater.ts b/src/utils/updater.ts index 2ea4953..04205a5 100644 --- a/src/utils/updater.ts +++ b/src/utils/updater.ts @@ -61,7 +61,7 @@ export function getRepo() { return Unwrap(VencordNative.ipc.invoke<IpcRes<string>>(IpcEvents.GET_REPO)); } -type Hashes = Record<"patcher.js" | "preload.js" | "renderer.js", string>; +type Hashes = Record<"patcher.js" | "preload.js" | "renderer.js" | "renderer.css", string>; /** * @returns true if hard restart is required diff --git a/src/webpack/common.tsx b/src/webpack/common.tsx index f2c42d1..a732d6b 100644 --- a/src/webpack/common.tsx +++ b/src/webpack/common.tsx @@ -36,6 +36,7 @@ export let React: typeof import("react"); export let useState: typeof React.useState; export let useEffect: typeof React.useEffect; export let useMemo: typeof React.useMemo; +export let useRef: typeof React.useRef; export const ReactDOM: typeof import("react-dom") = findByPropsLazy("createPortal", "render"); @@ -158,7 +159,7 @@ export const NavigationRouter = mapMangledModuleLazy("Transitioning to external waitFor("useState", m => { React = m; - ({ useEffect, useState, useMemo } = React); + ({ useEffect, useState, useMemo, useRef } = React); }); waitFor(["dispatch", "subscribe"], m => { |