diff --git a/Plugins/README.md b/Plugins/README.md index 829d5895d3..b854054d5e 100644 --- a/Plugins/README.md +++ b/Plugins/README.md @@ -39,5 +39,6 @@ - [Stalker Notifications](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/StalkerNotifications) - Lets you observe the status of people that aren't your friends. - [Steam Profile Link](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/SteamProfileLink) - Opens a steam profile in steam instead of a browser when clicking the steamlink in a userprofile. With the help of square. - [Theme Repo](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeRepo) - Allows you to preview all themes from the theme repo and download them on the fly. + - [Theme Settings](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeSettings) - Allows you to change Theme Variables within BetterDiscord. - [Top Role Everywhere](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/TopRoleEverywhere) - Adds the highest role of a user as a tag. - [Write UpperCase](https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/WriteUpperCase) - Changes the input in the textarea to uppercase. \ No newline at end of file diff --git a/Plugins/ThemeSettings/README.md b/Plugins/ThemeSettings/README.md new file mode 100644 index 0000000000..95cd134a0f --- /dev/null +++ b/Plugins/ThemeSettings/README.md @@ -0,0 +1,3 @@ +# Theme Repo - [Download](https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/ThemeSettings/ThemeSettings.plugin.js) + +Allows you to change Theme Variables within BetterDiscord. diff --git a/Plugins/ThemeSettings/ThemeSettings.plugin.js b/Plugins/ThemeSettings/ThemeSettings.plugin.js new file mode 100644 index 0000000000..b67217ed8d --- /dev/null +++ b/Plugins/ThemeSettings/ThemeSettings.plugin.js @@ -0,0 +1,206 @@ +//META{"name":"ThemeSettings"}*// + +class ThemeSettings { + initConstructor () {} + + getName () {return "ThemeSettings";} + + getDescription () {return "Allows you to change Theme Variables within BetterDiscord.";} + + getVersion () {return "1.0.0";} + + getAuthor () {return "DevilBro";} + + getSettingsPanel () {} + + //legacy + load () {} + + start () { + var libraryScript = null; + if (typeof BDFDB !== "object" || typeof BDFDB.isLibraryOutdated !== "function" || BDFDB.isLibraryOutdated()) { + libraryScript = document.querySelector('head script[src="https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js"]'); + if (libraryScript) libraryScript.remove(); + libraryScript = document.createElement("script"); + libraryScript.setAttribute("type", "text/javascript"); + libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js"); + document.head.appendChild(libraryScript); + } + this.startTimeout = setTimeout(() => {this.initialize();}, 30000); + if (typeof BDFDB === "object" && typeof BDFDB.isLibraryOutdated === "function") this.initialize(); + else libraryScript.addEventListener("load", () => {this.initialize();}); + } + + initialize () { + if (typeof BDFDB === "object") { + BDFDB.loadMessage(this); + + this.fs = require("fs"); + this.path = require("path"); + this.dir = BDFDB.getThemesFolder(); + + var observer = null; + observer = new MutationObserver((changes, _) => { + changes.forEach( + (change, j) => { + if (change.addedNodes) { + change.addedNodes.forEach((node) => { + if (node.tagName && node.querySelector(".ui-switch") && this.isThemesPage()) { + this.addSettingsButton(node); + } + }); + } + } + ); + }); + BDFDB.addObserver(this, BDFDB.dotCN.layer + "[layer-id='user-settings']", {name:"innerSettingsWindowObserver",instance:observer}, {childList:true,subtree:true}); + + observer = new MutationObserver((changes, _) => { + changes.forEach( + (change, i) => { + if (change.addedNodes) { + change.addedNodes.forEach((node) => { + setImmediate(() => { + if (node.tagName && node.getAttribute("layer-id") == "user-settings") { + BDFDB.addObserver(this, node, {name:"innerSettingsWindowObserver"}, {childList:true,subtree:true}); + } + }); + }); + } + } + ); + }); + BDFDB.addObserver(this, BDFDB.dotCN.layers, {name:"settingsWindowObserver",instance:observer}, {childList:true}); + + var settingswindow = document.querySelector(BDFDB.dotCN.layer + "[layer-id='user-settings']"); + if (settingswindow && this.isThemesPage(settingswindow)) { + for (let li of settingswindow.querySelectorAll(".bda-slist > li")) this.addSettingsButton(li); + } + } + else { + console.error(this.getName() + ": Fatal Error: Could not load BD functions!"); + } + } + + stop () { + if (typeof BDFDB === "object") { + $(".themes-settings-button, .themes-settings-footer").remove(); + + BDFDB.unloadMessage(this); + } + } + + // begin of own functions + + isThemesPage (container) { + if (typeof container === "undefined") container = document.querySelector(BDFDB.dotCN.layer + "[layer-id='user-settings']"); + if (container && container.tagName) { + var folderbutton = container.querySelector(".bd-pfbtn"); + if (folderbutton) { + var buttonbar = folderbutton.parentElement; + if (buttonbar && buttonbar.tagName) { + var header = buttonbar.querySelector("h2"); + if (header) { + return BDFDB.getInnerText(header).toLowerCase() === "themes"; + } + } + } + } + return false; + } + + addSettingsButton (li) { + if (li && li.tagName && li.tagName == "LI" && !li.querySelector(".bda-settings-button.themes-settings-button")) { + let nameele = li.querySelector(".bda-name"); + let name = nameele ? nameele.textContent : null; + if (name && bdthemes[name]) { + let vars = this.getThemeVars(bdthemes[name].css); + if (vars.length) { + let footer = li.querySelector(".bda-footer"); + if (!footer) { + footer = document.createElement("div"); + footer.className = "bda-footer themes-settings-footer"; + li.appendChild(footer); + } + let button = document.createElement("button"); + button.className = "bda-settings-button themes-settings-button"; + button.innerText = "Settings"; + footer.appendChild(button); + $(button).on("click." + this.getName(), () => { + li.classList.remove("settings-closed"); + li.classList.add("settings-open"); + let children = []; + while (li.childElementCount) { + children.push(li.firstChild); + li.firstChild.remove(); + } + $(`
`) + .on("click." + this.getName(), () => { + li.classList.remove("settings-open"); + li.classList.add("settings-closed"); + while (li.childElementCount) li.firstChild.remove(); + while (children.length) li.appendChild(children.shift()); + }) + .appendTo(li); + li.appendChild(this.createThemeSettings(name, vars)); + }); + } + } + } + } + + getThemeVars (css) { + let vars = css.split(":root"); + if (vars.length > 1) { + vars = vars[1].replace(/[\t\n\r]/g,"").replace(/\s{2,}/g," ").replace(/\/\*+.*?\*+\//g,""); + vars = vars.split("{"); + vars.shift(); + vars = vars.join("{").replace(/ (;|--)/g,"$1").replace(/(:) /g,"$1") + vars = vars.split(";}")[0].slice(2).split(";--"); + if (vars.length > 1) return vars; + } + return []; + } + + createThemeSettings (name, vars) { + if (!this.started || typeof BDFDB !== "object") return; + var settingshtml = `
${BDFDB.encodeToHTML(name)}

Update all variables

`; + for (let varstr of vars) { + varstr = varstr.split(":"); + let varname = varstr.shift(); + let varvalue = varstr.join(":"); + let iscontentvar = varvalue[0] == varvalue[varvalue.length-1] && (varvalue[0] == `"` || varvalue[0] == `'`); + varvalue = iscontentvar ? varvalue.slice(1,-1) : varvalue; + settingshtml += `

${varname}:

`; + } + settingshtml += `
`; + + var settingspanel = $(settingshtml)[0]; + + BDFDB.initElements(settingspanel); + + $(settingspanel).on("click", ".update-button", () => { + let path = this.path.join(this.dir, bdthemes[name].filename); + let css = this.fs.readFileSync(path).toString(); + if (css) { + let amount = 0; + for (let input of settingspanel.querySelectorAll(BDFDB.dotCN.input)) { + let oldvalue = input.getAttribute("placeholder"); + let newvalue = input.value; + if (newvalue && newvalue.trim() && newvalue != oldvalue) { + let varname = input.getAttribute("option"); + if (input.getAttribute("iscontent")) css = css.replace(new RegExp(`--${varname}(\\s*):(\\s*)(["'])${oldvalue}["']`,"g"),`--${varname}$1:$2$3${newvalue}$3`); + else css = css.replace(new RegExp(`--${varname}(\\s*):(\\s*)${oldvalue}`,"g"),`--${varname}$1:$2${newvalue}`); + amount++; + } + } + if (amount > 0) { + this.fs.writeFileSync(path, css); + BDFDB.showToast(`Updated ${amount} variable${amount == 1 ? "" : "s"} in ${bdthemes[name].filename}`, {type:"success"}); + } + } + else BDFDB.showToast(`Could not find themefile: ${bdthemes[name].filename}`, {type:"error"}); + }); + return settingspanel; + } +} \ No newline at end of file