diff options
-rwxr-xr-x | scripts/build/build.mjs | 9 | ||||
-rwxr-xr-x | scripts/build/buildWeb.mjs | 5 | ||||
-rw-r--r-- | scripts/build/common.mjs | 51 | ||||
-rw-r--r-- | src/components/Monaco.ts | 74 | ||||
-rw-r--r-- | src/components/Settings.tsx | 2 | ||||
-rw-r--r-- | src/components/monacoWin.html | 52 | ||||
-rw-r--r-- | src/ipcMain/index.ts | 20 | ||||
-rw-r--r-- | src/modules.d.ts | 5 | ||||
-rw-r--r-- | src/preload.ts | 15 | ||||
-rw-r--r-- | src/utils/IpcEvents.ts | 3 | ||||
-rw-r--r-- | src/utils/Queue.ts | 27 |
11 files changed, 173 insertions, 90 deletions
diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs index f6304b1..1986369 100755 --- a/scripts/build/build.mjs +++ b/scripts/build/build.mjs @@ -18,7 +18,7 @@ */ import esbuild from "esbuild"; -import { commonOpts, gitHashPlugin, globPlugins, makeAllPackagesExternalPlugin } from "./common.mjs"; +import { commonOpts, fileIncludePlugin, gitHashPlugin, globPlugins, makeAllPackagesExternalPlugin } from "./common.mjs"; /** * @type {esbuild.BuildOptions} @@ -30,7 +30,7 @@ const nodeCommonOpts = { target: ["esnext"], minify: true, sourcemap: "linked", - plugins: [makeAllPackagesExternalPlugin], + plugins: [...commonOpts.plugins, makeAllPackagesExternalPlugin], }; await Promise.all([ @@ -55,7 +55,8 @@ await Promise.all([ external: ["plugins", "git-hash"], plugins: [ globPlugins, - gitHashPlugin + gitHashPlugin, + fileIncludePlugin ], define: { IS_WEB: "false" @@ -65,6 +66,6 @@ await Promise.all([ console.error("Build failed"); console.error(err.message); // make ci fail - if (!watch) + if (!commonOpts.watch) process.exitCode = 1; }); diff --git a/scripts/build/buildWeb.mjs b/scripts/build/buildWeb.mjs index 8abac2c..286aad3 100755 --- a/scripts/build/buildWeb.mjs +++ b/scripts/build/buildWeb.mjs @@ -23,7 +23,7 @@ import yazl from "yazl"; import esbuild from "esbuild"; // wtf is this assert syntax import PackageJSON from "../../package.json" assert { type: "json" }; -import { commonOpts, gitHashPlugin, globPlugins } from "./common.mjs"; +import { commonOpts, fileIncludePlugin, gitHashPlugin, globPlugins } from "./common.mjs"; /** * @type {esbuild.BuildOptions} @@ -36,7 +36,8 @@ const commonOptions = { external: ["plugins", "git-hash"], plugins: [ globPlugins, - gitHashPlugin + gitHashPlugin, + fileIncludePlugin ], target: ["esnext"], define: { diff --git a/scripts/build/common.mjs b/scripts/build/common.mjs index 6143fb2..c3afc7f 100644 --- a/scripts/build/common.mjs +++ b/scripts/build/common.mjs @@ -19,22 +19,11 @@ import { execSync } from "child_process"; import esbuild from "esbuild"; import { existsSync } from "fs"; -import { readdir } from "fs/promises"; +import { readdir, readFile } from "fs/promises"; +import { join } from "path"; const watch = process.argv.includes("--watch"); -/** - * @type {esbuild.BuildOptions} - */ -export const commonOpts = { - logLevel: "info", - bundle: true, - watch, - minify: !watch, - sourcemap: watch ? "inline" : "", - legalComments: "linked" -}; - // https://github.com/evanw/esbuild/issues/619#issuecomment-751995294 /** * @type {esbuild.Plugin} @@ -103,3 +92,39 @@ export const gitHashPlugin = { })); } }; + +/** + * @type {esbuild.Plugin} + */ +export const fileIncludePlugin = { + name: "file-include-plugin", + setup: build => { + const filter = /^@fileContent\/.+$/; + build.onResolve({ filter }, args => ({ + namespace: "include-file", + path: args.path, + pluginData: { + path: join(args.resolveDir, args.path.slice("include-file/".length)) + } + })); + build.onLoad({ filter, namespace: "include-file" }, async ({ pluginData: { path } }) => { + const [name, format] = path.split(";"); + return { + contents: `export default ${JSON.stringify(await readFile(name, format ?? "utf-8"))}` + }; + }); + } +}; + +/** + * @type {esbuild.BuildOptions} + */ +export const commonOpts = { + logLevel: "info", + bundle: true, + watch, + minify: !watch, + sourcemap: watch ? "inline" : "", + legalComments: "linked", + plugins: [fileIncludePlugin] +}; diff --git a/src/components/Monaco.ts b/src/components/Monaco.ts index 495f512..6b01891 100644 --- a/src/components/Monaco.ts +++ b/src/components/Monaco.ts @@ -16,80 +16,26 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ - import { IpcEvents } from "../utils"; import { debounce } from "../utils/debounce"; import { find } from "../webpack/webpack"; +import monacoHtml from "@fileContent/monacoWin.html"; +import { Queue } from "../utils/Queue"; +const queue = new Queue(); const setCss = debounce((css: string) => { - VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, css); + queue.add(() => VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, css)); }); -// FIXME: Discord Desktop support. -// open() fails to create the popup and returns null. Probably have to -// do some logic in main - -// adapted from https://stackoverflow.com/a/63179814 export async function launchMonacoEditor() { const win = open("about:blank", void 0, "popup,width=1000,height=1000")!; + win.setCss = setCss; win.getCurrentCss = () => VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS); - win.callback = (editor: any) => { - editor.onDidChangeModelContent(() => - setCss(editor.getValue()) - ); - }; - - let { theme } = find(m => m.ProtoClass?.typeName.endsWith("PreloadedUserSettings")) - .getCurrentValue().appearance; - theme = theme === 1 ? "vs-dark" : "vs-light"; - - // problem? - win.document.write(` - - <!doctype html> - <html lang="en"> - <head> - <meta charset="utf-8"> - <title>QuickCss Editor</title> - <link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/editor/editor.main.min.css"> - <style> - html, body, #container { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - overflow: hidden; - } - </style> - </head> - <body> - <div id="container"></div> - <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/loader.min.js"></script> - - <script> - var editor; - require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs' }}); - require(["vs/editor/editor.main"], () => { - getCurrentCss().then(css => { - callback(editor = monaco.editor.create(document.getElementById('container'), { - value: css, - language: 'css', - theme: '${theme}', - })); - }); - }); - - window.addEventListener("resize", () => { - // make monaco re-layout - editor.layout(); - }); - </script> - </body> - </html> + win.getTheme = () => find(m => m.ProtoClass?.typeName.endsWith("PreloadedUserSettings")) + .getCurrentValue().appearance.theme === 1 + ? "vs-dark" + : "vs-light"; -`); + win.document.write(monacoHtml); } diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index 6a5ea9d..8ffe111 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -77,7 +77,7 @@ export default ErrorBoundary.wrap(function Settings() { Launch Directory </Button> <Button - onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_QUICKCSS)} + onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_MONACO_EDITOR)} size={Button.Sizes.SMALL} disabled={settingsDir === "Loading..."} > diff --git a/src/components/monacoWin.html b/src/components/monacoWin.html new file mode 100644 index 0000000..edf273d --- /dev/null +++ b/src/components/monacoWin.html @@ -0,0 +1,52 @@ +<!doctype html> +<html lang="en"> + +<head> + <meta charset="utf-8"> + <title>QuickCss Editor</title> + <link rel="stylesheet" data-name="vs/editor/editor.main" + href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/editor/editor.main.min.css"> + <style> + html, + body, + #container { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + overflow: hidden; + } + </style> +</head> + +<body> + <div id="container"></div> + <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs/loader.min.js"></script> + + <script> + require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs' } }); + require(["vs/editor/editor.main"], () => { + getCurrentCss().then(css => { + var editor = monaco.editor.create(document.getElementById('container'), { + value: css, + language: 'css', + theme: getTheme(), + }); + editor.onDidChangeModelContent(() => + setCss(editor.getValue()) + ); + window.addEventListener("resize", () => { + // make monaco re-layout + editor.layout(); + }); + }); + }); + + + </script> +</body> + +</html> diff --git a/src/ipcMain/index.ts b/src/ipcMain/index.ts index caa4e34..dc05079 100644 --- a/src/ipcMain/index.ts +++ b/src/ipcMain/index.ts @@ -22,8 +22,10 @@ import { open, readFile, writeFile } from "fs/promises"; import { join } from "path"; import { debounce } from "../utils/debounce"; import IpcEvents from "../utils/IpcEvents"; +import monacoHtml from "@fileContent/../components/monacoWin.html;base64"; import "./updater"; +import { Queue } from "../utils/Queue"; const DATA_DIR = process.env.VENCORD_USER_DATA_DIR ?? ( process.env.DISCORD_USER_DATA_DIR @@ -71,15 +73,19 @@ ipcMain.handle(IpcEvents.OPEN_EXTERNAL, (_, url) => { shell.openExternal(url); }); +const cssWriteQueue = new Queue(); +const settingsWriteQueue = new Queue(); ipcMain.handle(IpcEvents.GET_QUICK_CSS, () => readCss()); +ipcMain.handle(IpcEvents.SET_QUICK_CSS, (_, css) => + cssWriteQueue.add(() => writeFile(QUICKCSS_PATH, css)) +); ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR); ipcMain.on(IpcEvents.GET_SETTINGS, e => e.returnValue = readSettings()); -let settingsWriteQueue = Promise.resolve(); ipcMain.handle(IpcEvents.SET_SETTINGS, (_, s) => { - settingsWriteQueue = settingsWriteQueue.then(() => writeFile(SETTINGS_FILE, s)); + settingsWriteQueue.add(() => writeFile(SETTINGS_FILE, s)); }); @@ -91,3 +97,13 @@ export function initIpc(mainWindow: BrowserWindow) { }, 50)); }); } + +ipcMain.handle(IpcEvents.OPEN_MONACO_EDITOR, async () => { + const win = new BrowserWindow({ + title: "QuickCss Editor", + webPreferences: { + preload: join(__dirname, "preload.js"), + } + }); + await win.loadURL(`data:text/html;base64,${monacoHtml}`); +}); diff --git a/src/modules.d.ts b/src/modules.d.ts index 11576d2..70bad2f 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -28,3 +28,8 @@ declare module "git-hash" { const hash: string; export default hash; } + +declare module "@fileContent/*" { + const content: string; + export default content; +} diff --git a/src/preload.ts b/src/preload.ts index 7244a1d..5de4298 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -21,6 +21,7 @@ import { readFileSync } from "fs"; import { join } from "path"; import VencordNative from "./VencordNative"; import IpcEvents from "./utils/IpcEvents"; +import { debounce } from "./utils/debounce"; if (electron.desktopCapturer === void 0) { // Fix for desktopCapturer being main only in Electron 17+ @@ -39,6 +40,14 @@ if (electron.desktopCapturer === void 0) { contextBridge.exposeInMainWorld("VencordNative", VencordNative); -webFrame.executeJavaScript(readFileSync(join(__dirname, "renderer.js"), "utf-8")); - -require(process.env.DISCORD_PRELOAD!); +if (location.protocol !== "data:") { + // Discord + webFrame.executeJavaScript(readFileSync(join(__dirname, "renderer.js"), "utf-8")); + require(process.env.DISCORD_PRELOAD!); +} else { + // Monaco Popout + contextBridge.exposeInMainWorld("setCss", debounce(s => VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, s))); + contextBridge.exposeInMainWorld("getCurrentCss", () => VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS)); + // shrug + contextBridge.exposeInMainWorld("getTheme", () => "vs-dark"); +} diff --git a/src/utils/IpcEvents.ts b/src/utils/IpcEvents.ts index b773f64..c6696f8 100644 --- a/src/utils/IpcEvents.ts +++ b/src/utils/IpcEvents.ts @@ -43,5 +43,6 @@ export default strEnum({ GET_HASHES: "VencordGetHashes", UPDATE: "VencordUpdate", BUILD: "VencordBuild", - GET_DESKTOP_CAPTURE_SOURCES: "VencordGetDesktopCaptureSources" + GET_DESKTOP_CAPTURE_SOURCES: "VencordGetDesktopCaptureSources", + OPEN_MONACO_EDITOR: "VencordOpenMonacoEditor" } as const); diff --git a/src/utils/Queue.ts b/src/utils/Queue.ts new file mode 100644 index 0000000..269fd36 --- /dev/null +++ b/src/utils/Queue.ts @@ -0,0 +1,27 @@ +/* + * 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 { Promisable } from "type-fest"; + +export class Queue { + private promise = Promise.resolve(); + + add(func: () => Promisable<void>) { + this.promise = this.promise.then(func); + } +} |