parent
2172cae779
commit
2e5d27b6b6
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
(window.VencordStyles ??= new Map()).set(STYLE_NAME, {
|
||||
name: STYLE_NAME,
|
||||
source: STYLE_SOURCE,
|
||||
classNames: {},
|
||||
dom: null,
|
||||
});
|
||||
|
||||
export default STYLE_NAME;
|
@ -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(" ");
|
||||
};
|
@ -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");
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
@ -0,0 +1 @@
|
||||
@import url('https://cdn.jsdelivr.net/gh/devicons/devicon@v2.10.1/devicon.min.css');
|
Loading…
Reference in new issue