@@ -215,10 +446,37 @@ function ThemesTab() {
if (fileName.endsWith(".user.css")) {
// handle it as usercss
+ const header = await usercssParse(content, fileName);
+
themeInfo.push({
type: "usercss",
- header: usercssParse(content, fileName)
+ header
});
+
+ Settings.userCssVars[header.id] ??= {};
+
+ for (const [name, varInfo] of Object.entries(header.vars ?? {})) {
+ let normalizedValue = "";
+
+ switch (varInfo.type) {
+ case "text":
+ case "color":
+ case "select":
+ normalizedValue = varInfo.default;
+ break;
+ case "checkbox":
+ normalizedValue = varInfo.default ? "1" : "0";
+ break;
+ case "range":
+ normalizedValue = `${varInfo.default}${varInfo.units}`;
+ break;
+ case "number":
+ normalizedValue = String(varInfo.default);
+ break;
+ }
+
+ Settings.userCssVars[header.id][name] ??= normalizedValue;
+ }
} else {
// presumably BD but could also be plain css
themeInfo.push({
diff --git a/src/utils/quickCss.ts b/src/utils/quickCss.ts
index ad9642ac3..c70c880f4 100644
--- a/src/utils/quickCss.ts
+++ b/src/utils/quickCss.ts
@@ -99,6 +99,7 @@ document.addEventListener("DOMContentLoaded", () => {
addSettingsListener("themeLinks", initThemes);
addSettingsListener("enabledThemes", initThemes);
+ addSettingsListener("userCssVars", initThemes);
if (!IS_WEB)
VencordNative.quickCss.addThemeChangeListener(initThemes);
diff --git a/src/utils/themes/usercss/compiler.ts b/src/utils/themes/usercss/compiler.ts
index 6844a0c86..7785e42ae 100644
--- a/src/utils/themes/usercss/compiler.ts
+++ b/src/utils/themes/usercss/compiler.ts
@@ -62,7 +62,7 @@ export async function compileUsercss(fileName: string) {
// - use the preprocessor defined
// - if variables are set, `uso`
// - otherwise, `default`
- const { vars = {}, preprocessor = Object.keys(vars).length > 0 ? "uso" : "default" } = usercssParse(themeData, fileName);
+ const { vars = {}, preprocessor = Object.keys(vars).length > 0 ? "uso" : "default", id } = await usercssParse(themeData, fileName);
const preprocessorFn = preprocessors[preprocessor];
@@ -74,7 +74,7 @@ export async function compileUsercss(fileName: string) {
const varsToPass = {};
for (const [k, v] of Object.entries(vars)) {
- varsToPass[k] = Settings.userCssVars[fileName]?.[k] ?? v.default;
+ varsToPass[k] = Settings.userCssVars[id]?.[k] ?? v.default;
}
try {
diff --git a/src/utils/themes/usercss/index.ts b/src/utils/themes/usercss/index.ts
index 3c51e38f1..f83d293fe 100644
--- a/src/utils/themes/usercss/index.ts
+++ b/src/utils/themes/usercss/index.ts
@@ -9,7 +9,7 @@ import { parse as originalParse, UserstyleHeader } from "usercss-meta";
const UserCSSLogger = new Logger("UserCSS", "#d2acf5");
-export function usercssParse(text: string, fileName: string): UserstyleHeader {
+export async function usercssParse(text: string, fileName: string): Promise
{
var { metadata, errors } = originalParse(text.replace(/\r/g, ""), { allowErrors: true });
if (errors.length) {
@@ -19,5 +19,20 @@ export function usercssParse(text: string, fileName: string): UserstyleHeader {
return {
...metadata,
fileName,
+ id: await getUserCssId(metadata)
};
}
+
+export async function getUserCssId(header: UserstyleHeader): Promise {
+ const encoder = new TextEncoder();
+
+ const nameBuf = encoder.encode(header.name);
+ const namespaceBuf = encoder.encode(header.namespace);
+
+ const nameHash = new Uint8Array(await window.crypto.subtle.digest("SHA-256", nameBuf));
+ const namespaceHash = new Uint8Array(await window.crypto.subtle.digest("SHA-256", namespaceBuf));
+
+ const idHash = await window.crypto.subtle.digest("SHA-256", new Uint8Array([...nameHash, ...namespaceHash]));
+
+ return window.btoa(String.fromCharCode(...new Uint8Array(idHash)));
+}
diff --git a/src/utils/themes/usercss/usercss-meta.d.ts b/src/utils/themes/usercss/usercss-meta.d.ts
index d51304591..1a39bf6d2 100644
--- a/src/utils/themes/usercss/usercss-meta.d.ts
+++ b/src/utils/themes/usercss/usercss-meta.d.ts
@@ -36,11 +36,18 @@ declare module "usercss-meta" {
| {
type: "select";
default: string;
- options: Record;
+ options: { name: string; label: string; value: string; }[];
}
)>;
export interface UserstyleHeader {
+ /**
+ * The unique ID of the UserCSS style.
+ *
+ * @vencord Specific to Vencord, not part of the original module.
+ */
+ id: string;
+
/**
* The file name of the UserCSS style.
*
diff --git a/src/webpack/common/types/components.d.ts b/src/webpack/common/types/components.d.ts
index 4b316aad6..3101b2859 100644
--- a/src/webpack/common/types/components.d.ts
+++ b/src/webpack/common/types/components.d.ts
@@ -190,7 +190,7 @@ export type TextArea = ComponentType>;
-interface SelectOption {
+export interface SelectOption {
disabled?: boolean;
value: any;
label: string;