diff --git a/Plugins/ThemeSettings/ThemeSettings.plugin.js b/Plugins/ThemeSettings/ThemeSettings.plugin.js index cfa5f99c5f..330d17d512 100644 --- a/Plugins/ThemeSettings/ThemeSettings.plugin.js +++ b/Plugins/ThemeSettings/ThemeSettings.plugin.js @@ -2,7 +2,7 @@ * @name ThemeSettings * @author DevilBro * @authorId 278543574059057154 - * @version 1.3.2 + * @version 1.3.3 * @description Allows you to change Theme Variables within Discord. Adds a Settings button (similar to Plugins) to customizable Themes in your Themes Page * @invite Jx3TjNS * @donate https://www.paypal.me/MircoWittrien @@ -17,8 +17,13 @@ module.exports = (_ => { "info": { "name": "ThemeSettings", "author": "DevilBro", - "version": "1.3.2", + "version": "1.3.3", "description": "Allows you to change Theme Variables within Discord. Adds a Settings button (similar to Plugins) to customizable Themes in your Themes Page" + }, + "changeLog": { + "added": { + "Reset": "Added a Button to reset all Values back to the Value that was used when you opened the Settings" + } } }; @@ -59,9 +64,7 @@ module.exports = (_ => { template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); return template.content.firstElementChild; } - } : (([Plugin, BDFDB]) => { - const isBeta = !(window.BdApi && !Array.isArray(BdApi.settings)); - + } : (([Plugin, BDFDB]) => { var dir; return class ThemeSettings extends Plugin { @@ -103,11 +106,26 @@ module.exports = (_ => { let addon = BDFDB.ObjectUtils.get(BDFDB.ReactUtils.getInstance(card), "return.stateNode.props.addon"); if (addon && !addon.plugin && !addon.instance && addon.css) { let css = addon.css.replace(/\r/g, ""); - let imports = this.getThemeImports(css); - let vars = this.getThemeVars(css); + let imports = css.split("\n@import url(").splice(1).map(n => [n.split(");")[0], true]).concat(css.split("\n/* @import url(").splice(1).map(n => [n.split("); */")[0], false])); + let vars = css.split(":root"); + if (vars.length > 1) { + vars = vars[1].replace(/\t\(/g, " (").replace(/\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); + vars = vars.split("{"); + vars.shift(); + vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); + vars = vars.split("}")[0]; + vars = (vars.endsWith(";") ? vars.slice(0, -1) : vars).slice(2).split(/;--|\*\/--/); + } + else vars = []; + if (imports.length || vars.length) { - let open = _ => { - let refs = {imports: {}, inputs: {}}; + let footerControls = card.querySelector(BDFDB.dotCNS._repofooter + BDFDB.dotCN._repocontrols); + let settingsButton = document.createElement("button"); + settingsButton.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repobutton, BDFDB.disCN._repocontrolsbutton, "theme-settings-button"); + settingsButton.appendChild(BDFDB.DOMUtils.create(``)); + footerControls.insertBefore(settingsButton, footerControls.firstElementChild); + settingsButton.addEventListener("click", _ => { + let importInstances = {}, inputInstances = {}; BDFDB.ModalUtils.open(this, { header: `${addon.name} ${BDFDB.LanguageUtils.LanguageStrings.SETTINGS}`, subHeader: "", @@ -116,76 +134,133 @@ module.exports = (_ => { contentClassName: BDFDB.disCN._repomodalsettings, footerClassName: BDFDB.disCN._repomodalfooter, size: "MEDIUM", - children: this.createThemeInputs(refs, addon, imports, vars), + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanel, { + addon: addon, + children: _ => { + let settingsItems = []; + + let varInputs = []; + for (let i in vars) { + let varStr = vars[i].split(":"); + let varName = varStr.shift().trim(); + varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); + let varValue = varStr.shift().trim(); + if (varValue) { + let childType = "text", childMode = ""; + let isColor = BDFDB.ColorUtils.getType(varValue); + let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(varValue); + if (isColor || isComp) { + childType = "color"; + childMode = isComp && "comp"; + } + else { + let isUrlFile = /url\(.+\)/gi.test(varValue); + let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(varValue); + if (isFile || isUrlFile) { + childType = "file"; + childMode = isUrlFile && "url"; + } + } + let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); + varInputs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "TextInput", + margin: 8, + childProps: { + type: childType, + mode: childMode, + filter: childType == "file" && "image", + ref: instance => {if (instance) inputInstances[i] = instance;} + }, + label: varName.split("-").map(BDFDB.LibraryModules.StringUtils.upperCaseFirstChar).join(" "), + note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, + basis: "70%", + name: varName, + value: varValue, + oldValue: varValue, + defaultValue: varValue, + placeholder: varValue + })); + } + }; + + if (imports.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Imports:", + dividerBottom: varInputs.length, + children: imports.map((impo, i) => { + let name = impo[0].split("/").pop().replace(/"/g, ""); + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 8, + childProps: {ref: instance => {if (instance) importInstances[i] = instance;}}, + label: name[0].toUpperCase() + name.slice(1), + note: impo[0].replace(/"/g, ""), + name: impo[0], + value: impo[1], + oldValue: impo[1].toString(), + defaultValue: impo[1].toString() + }); + }) + })); + if (varInputs.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Variables:", + children: varInputs + })); + + return settingsItems; + } + }), buttons: [{ contents: BDFDB.LanguageUtils.LanguageStrings.SAVE, color: "BRAND", - onClick: _ => {this.updateTheme(refs, addon);} + onClick: _ => this.updateTheme(addon, {imports: importInstances, inputs: inputInstances}, false) + }, { + contents: BDFDB.LanguageUtils.LanguageStrings.RESET, + look: "LINK", + onClick: _ => this.updateTheme(addon, {imports: importInstances, inputs: inputInstances}, true) }] }); - }; - if (isBeta) { - let controls = card.querySelector("." + BDFDB.disCN._repofooter.split(" ")[0] + " " + BDFDB.dotCN._repocontrols); - let settingsButton = document.createElement("button"); - settingsButton.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repobutton, BDFDB.disCN._repocontrolsbutton, "theme-settings-button"); - settingsButton.appendChild(BDFDB.DOMUtils.create(``)); - controls.insertBefore(settingsButton, controls.firstElementChild); - settingsButton.addEventListener("click", open); - settingsButton.addEventListener("mouseenter", _ => { - BDFDB.TooltipUtils.create(settingsButton, BDFDB.LanguageUtils.LanguageStrings.SETTINGS); - }); - } - else { - let footer = card.querySelector("." + BDFDB.disCN._repofooter.split(" ").join(",.")); - if (!footer) { - footer = document.createElement("div"); - footer.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repofooter); - let links = document.createElement("span"); - links.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repolinks); - footer.appendChild(links); - card.appendChild(footer); - } - let settingsButton = document.createElement("button"); - settingsButton.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._reposettingsbutton, "theme-settings-button"); - settingsButton.innerText = "Settings"; - footer.appendChild(settingsButton); - settingsButton.addEventListener("click", open); - } + }); + settingsButton.addEventListener("mouseenter", _ => { + BDFDB.TooltipUtils.create(settingsButton, BDFDB.LanguageUtils.LanguageStrings.SETTINGS); + }); } } } - updateTheme (refs, addon) { + updateTheme (addon, instances, reset) { let path = BDFDB.LibraryRequires.path.join(dir, addon.filename); let css = BDFDB.LibraryRequires.fs.readFileSync(path).toString(); if (css) { let amount = 0; - for (let i in refs.imports) { - let input = refs.imports[i]; + for (let i in instances.imports) { + let input = instances.imports[i]; let oldValue = input.props.oldValue; - let newValue = input.props.value; + let newValue = reset ? input.props.defaultValue : input.props.value; if (newValue.toString() != oldValue.toString()) { + let trueValue = typeof newValue == "string" ? newValue == "true" : newValue; let importUrl = input.props.name; - if (newValue) css = css.replace(new RegExp(`\\n${BDFDB.StringUtils.regEscape("/* @import url(" + importUrl + "); */")}`, "g"), `\n@import url(${importUrl});`); + if (trueValue) css = css.replace(new RegExp(`\\n${BDFDB.StringUtils.regEscape("/* @import url(" + importUrl + "); */")}`, "g"), `\n@import url(${importUrl});`); else css = css.replace(new RegExp(`\\n${BDFDB.StringUtils.regEscape("@import url(" + importUrl + ");")}`, "g"), `\n/* @import url(${importUrl}); */`); + input.props.value = trueValue; input.props.oldValue = newValue; amount++; } } - for (let i in refs.inputs) { - let input = refs.inputs[i]; + for (let i in instances.inputs) { + let input = instances.inputs[i]; let oldValue = input.props.oldValue; - let newValue = input.props.value; + let newValue = reset ? input.props.defaultValue : input.props.value; if (newValue && newValue.trim() && newValue != oldValue) { let varName = input.props.name; css = css.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(varName)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(oldValue)}`,"g"), `--${varName}$1: $2${newValue}`); + input.props.value = newValue; input.props.oldValue = newValue; input.props.placeholder = newValue; amount++; } } if (amount > 0) { - BDFDB.ReactUtils.forceUpdate(BDFDB.ObjectUtils.toArray(refs.imports), BDFDB.ObjectUtils.toArray(refs.inputs)); + BDFDB.ReactUtils.forceUpdate(BDFDB.ObjectUtils.toArray(instances.imports), BDFDB.ObjectUtils.toArray(instances.inputs)); BDFDB.LibraryRequires.fs.writeFileSync(path, css); BDFDB.NotificationUtils.toast(`Updated ${amount} Variable${amount == 1 ? "" : "s"} in '${addon.filename}'`, {type: "success"}); } @@ -193,101 +268,6 @@ module.exports = (_ => { } else BDFDB.NotificationUtils.toast(`Could not find Theme File '${addon.filename}'`, {type: "danger"}); } - - getThemeImports (css) { - return css.split("\n@import url(").splice(1).map(n => [n.split(");")[0], true]).concat(css.split("\n/* @import url(").splice(1).map(n => [n.split("); */")[0], false])); - } - - getThemeVars (css) { - let vars = css.split(":root"); - if (vars.length > 1) { - vars = vars[1].replace(/\t\(/g, " (").replace(/\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); - vars = vars.split("{"); - vars.shift(); - vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); - vars = vars.split("}")[0]; - return (vars.endsWith(";") ? vars.slice(0, -1) : vars).slice(2).split(/;--|\*\/--/); - } - return []; - } - - createThemeInputs (refs, theme, imports, vars) { - let settingsPanel; - return settingsPanel = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanel, { - addon: theme, - children: _ => { - let settingsItems = []; - - if (imports.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { - title: "Imports:", - dividerBottom: vars.length, - children: imports.map((impo, i) => { - let name = impo[0].split("/").pop().replace(/"/g, ""); - return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - type: "Switch", - margin: 8, - childProps: { - ref: instance => {if (instance) refs.imports[i] = instance;} - }, - label: name[0].toUpperCase() + name.slice(1), - note: impo[0].replace(/"/g, ""), - name: impo[0], - value: impo[1], - oldValue: impo[1].toString() - }); - }) - })); - let varInputs = []; - for (let i in vars) { - let varStr = vars[i].split(":"); - let varName = varStr.shift().trim(); - varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); - let varValue = varStr.shift().trim(); - if (varValue) { - let childType = "text", childMode = ""; - let isColor = BDFDB.ColorUtils.getType(varValue); - let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(varValue); - if (isColor || isComp) { - childType = "color"; - childMode = isComp && "comp"; - } - else { - let isUrlFile = /url\(.+\)/gi.test(varValue); - let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(varValue); - if (isFile || isUrlFile) { - childType = "file"; - childMode = isUrlFile && "url"; - } - } - let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); - varInputs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { - type: "TextInput", - margin: 8, - childProps: { - type: childType, - mode: childMode, - filter: childType == "file" && "image", - ref: instance => {if (instance) refs.inputs[i] = instance;} - }, - label: varName[0].toUpperCase() + varName.slice(1), - note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, - basis: "70%", - name: varName, - value: varValue, - oldValue: varValue, - placeholder: varValue - })); - } - }; - if (varInputs.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { - title: "Variables:", - children: varInputs - })); - - return settingsItems; - } - }); - } }; })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); })(); \ No newline at end of file