2020-10-20 23:25:34 +02:00
/ * *
* @ name ThemeSettings
2021-03-05 13:26:41 +01:00
* @ author DevilBro
2020-10-20 23:25:34 +02:00
* @ authorId 278543574059057154
2021-05-12 15:30:56 +02:00
* @ version 1.3 . 3
2021-03-05 13:26:41 +01:00
* @ description Allows you to change Theme Variables within Discord . Adds a Settings button ( similar to Plugins ) to customizable Themes in your Themes Page
2020-10-20 23:25:34 +02:00
* @ invite Jx3TjNS
* @ donate https : //www.paypal.me/MircoWittrien
* @ patreon https : //www.patreon.com/MircoWittrien
2021-03-09 15:10:55 +01:00
* @ website https : //mwittrien.github.io/
* @ source https : //github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeSettings/
2021-03-10 09:17:37 +01:00
* @ updateUrl https : //mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeSettings/ThemeSettings.plugin.js
2020-10-20 23:25:34 +02:00
* /
2018-12-11 19:43:51 +01:00
2020-09-19 20:49:33 +02:00
module . exports = ( _ => {
2020-10-09 21:09:35 +02:00
const config = {
2020-09-19 20:49:33 +02:00
"info" : {
"name" : "ThemeSettings" ,
"author" : "DevilBro" ,
2021-05-12 15:30:56 +02:00
"version" : "1.3.3" ,
2021-03-05 11:21:21 +01:00
"description" : "Allows you to change Theme Variables within Discord. Adds a Settings button (similar to Plugins) to customizable Themes in your Themes Page"
2021-05-12 15:30:56 +02:00
} ,
"changeLog" : {
"added" : {
"Reset" : "Added a Button to reset all Values back to the Value that was used when you opened the Settings"
}
2020-03-28 07:55:39 +01:00
}
2020-09-19 20:49:33 +02:00
} ;
2020-11-13 19:47:44 +01:00
2022-02-05 21:14:17 +01:00
return ! window . BDFDB _Global || ( ! window . BDFDB _Global . loaded && ! window . BDFDB _Global . started ) ? class {
2021-01-06 12:38:36 +01:00
getName ( ) { return config . info . name ; }
getAuthor ( ) { return config . info . author ; }
getVersion ( ) { return config . info . version ; }
2021-02-01 17:13:13 +01:00
getDescription ( ) { return ` The Library Plugin needed for ${ config . info . name } is missing. Open the Plugin Settings to download it. \n \n ${ config . info . description } ` ; }
downloadLibrary ( ) {
require ( "request" ) . get ( "https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js" , ( e , r , b ) => {
2021-03-05 13:14:18 +01:00
if ( ! e && b && r . statusCode == 200 ) require ( "fs" ) . writeFile ( require ( "path" ) . join ( BdApi . Plugins . folder , "0BDFDB.plugin.js" ) , b , _ => BdApi . showToast ( "Finished downloading BDFDB Library" , { type : "success" } ) ) ;
2021-03-06 14:59:48 +01:00
else BdApi . alert ( "Error" , "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library" ) ;
2021-02-01 17:13:13 +01:00
} ) ;
}
2020-05-22 21:17:02 +02:00
2021-01-06 12:38:36 +01:00
load ( ) {
2020-11-19 16:51:14 +01:00
if ( ! window . BDFDB _Global || ! Array . isArray ( window . BDFDB _Global . pluginQueue ) ) window . BDFDB _Global = Object . assign ( { } , window . BDFDB _Global , { pluginQueue : [ ] } ) ;
2020-09-19 20:49:33 +02:00
if ( ! window . BDFDB _Global . downloadModal ) {
window . BDFDB _Global . downloadModal = true ;
2021-01-14 16:14:44 +01:00
BdApi . showConfirmationModal ( "Library Missing" , ` The Library Plugin needed for ${ config . info . name } is missing. Please click "Download Now" to install it. ` , {
2020-09-19 20:49:33 +02:00
confirmText : "Download Now" ,
cancelText : "Cancel" ,
onCancel : _ => { delete window . BDFDB _Global . downloadModal ; } ,
2020-09-20 08:15:13 +02:00
onConfirm : _ => {
delete window . BDFDB _Global . downloadModal ;
2021-02-01 17:13:13 +01:00
this . downloadLibrary ( ) ;
2020-09-20 08:15:13 +02:00
}
2020-09-19 20:49:33 +02:00
} ) ;
2020-03-28 07:55:39 +01:00
}
2020-09-19 20:49:33 +02:00
if ( ! window . BDFDB _Global . pluginQueue . includes ( config . info . name ) ) window . BDFDB _Global . pluginQueue . push ( config . info . name ) ;
2020-10-09 21:09:35 +02:00
}
2021-01-06 12:38:36 +01:00
start ( ) { this . load ( ) ; }
stop ( ) { }
getSettingsPanel ( ) {
2020-11-28 23:12:09 +01:00
let template = document . createElement ( "template" ) ;
2021-01-14 16:14:44 +01:00
template . innerHTML = ` <div style="color: var(--header-primary); font-size: 16px; font-weight: 300; white-space: pre; line-height: 22px;">The Library Plugin needed for ${ config . info . name } is missing. \n Please click <a style="font-weight: 500;">Download Now</a> to install it.</div> ` ;
2021-02-01 17:13:13 +01:00
template . content . firstElementChild . querySelector ( "a" ) . addEventListener ( "click" , this . downloadLibrary ) ;
2020-11-28 23:12:09 +01:00
return template . content . firstElementChild ;
}
2021-05-12 15:30:56 +02:00
} : ( ( [ Plugin , BDFDB ] ) => {
2020-09-19 20:49:33 +02:00
var dir ;
2020-10-09 21:09:35 +02:00
return class ThemeSettings extends Plugin {
2021-01-06 12:38:36 +01:00
onLoad ( ) {
2020-09-19 20:49:33 +02:00
dir = BDFDB . BDUtils . getThemesFolder ( ) ;
2021-02-09 12:57:45 +01:00
this . patchedModules = {
after : {
SettingsView : "componentDidMount"
}
} ;
2020-09-19 20:49:33 +02:00
}
2021-01-06 12:38:36 +01:00
onStart ( ) {
2021-02-09 12:57:45 +01:00
this . addListObserver ( document . querySelector ( ` ${ BDFDB . dotCN . layer } [aria-label=" ${ BDFDB . DiscordConstants . Layers . USER _SETTINGS } "] ` ) ) ;
BDFDB . ReactUtils . forceUpdate ( this ) ;
2020-03-28 07:55:39 +01:00
}
2020-09-19 20:49:33 +02:00
2021-01-06 12:38:36 +01:00
onStop ( ) {
2020-05-22 21:17:02 +02:00
BDFDB . DOMUtils . remove ( ".theme-settings-button" ) ;
2020-03-28 07:55:39 +01:00
}
2021-02-09 12:57:45 +01:00
processSettingsView ( e ) {
if ( e . node && e . node . parentElement && e . node . parentElement . getAttribute ( "aria-label" ) == BDFDB . DiscordConstants . Layers . USER _SETTINGS ) this . addListObserver ( e . node . parentElement ) ;
}
addListObserver ( layer ) {
if ( ! layer ) return ;
BDFDB . ObserverUtils . connect ( this , layer , { name : "cardObserver" , instance : new MutationObserver ( changes => { changes . forEach ( change => { if ( change . addedNodes ) { change . addedNodes . forEach ( node => {
if ( BDFDB . DOMUtils . containsClass ( node , BDFDB . disCN . _repocard ) ) this . appendSettingsButton ( node ) ;
if ( node . nodeType != Node . TEXT _NODE ) for ( let child of node . querySelectorAll ( BDFDB . dotCN . _repocard ) ) this . appendSettingsButton ( child ) ;
} ) ; } } ) ; } ) } , { childList : true , subtree : true } ) ;
for ( let child of layer . querySelectorAll ( BDFDB . dotCN . _repocard ) ) this . appendSettingsButton ( child ) ;
}
2020-05-22 21:17:02 +02:00
2020-09-19 20:49:33 +02:00
appendSettingsButton ( card ) {
if ( card . querySelector ( ".theme-settings-button" ) ) return ;
let addon = BDFDB . ObjectUtils . get ( BDFDB . ReactUtils . getInstance ( card ) , "return.stateNode.props.addon" ) ;
2020-10-24 10:00:00 +02:00
if ( addon && ! addon . plugin && ! addon . instance && addon . css ) {
2020-12-19 19:53:11 +01:00
let css = addon . css . replace ( /\r/g , "" ) ;
2021-05-12 15:30:56 +02:00
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 = [ ] ;
2020-12-19 19:53:11 +01:00
if ( imports . length || vars . length ) {
2021-05-12 15:30:56 +02:00
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 ( ` <svg viewBox="0 0 20 20" style="width: 20px; height: 20px;"><path fill="none" d="M0 0h20v20H0V0z"></path><path d="M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z"></path></svg> ` ) ) ;
footerControls . insertBefore ( settingsButton , footerControls . firstElementChild ) ;
settingsButton . addEventListener ( "click" , _ => {
let importInstances = { } , inputInstances = { } ;
2020-11-23 17:52:58 +01:00
BDFDB . ModalUtils . open ( this , {
header : ` ${ addon . name } ${ BDFDB . LanguageUtils . LanguageStrings . SETTINGS } ` ,
2021-01-23 18:50:24 +01:00
subHeader : "" ,
2020-11-23 17:52:58 +01:00
className : BDFDB . disCN . _repomodal ,
2020-11-23 20:19:58 +01:00
headerClassName : BDFDB . disCN . _repomodalheader ,
contentClassName : BDFDB . disCN . _repomodalsettings ,
footerClassName : BDFDB . disCN . _repomodalfooter ,
2020-11-23 17:52:58 +01:00
size : "MEDIUM" ,
2021-05-12 15:30:56 +02:00
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 ;
}
} ) ,
2021-01-29 20:57:25 +01:00
buttons : [ {
contents : BDFDB . LanguageUtils . LanguageStrings . SAVE ,
color : "BRAND" ,
2021-05-12 15:30:56 +02:00
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 )
2021-01-29 20:57:25 +01:00
} ]
2020-11-23 17:52:58 +01:00
} ) ;
2021-05-12 15:30:56 +02:00
} ) ;
settingsButton . addEventListener ( "mouseenter" , _ => {
BDFDB . TooltipUtils . create ( settingsButton , BDFDB . LanguageUtils . LanguageStrings . SETTINGS ) ;
} ) ;
2020-09-19 20:49:33 +02:00
}
2020-03-28 07:55:39 +01:00
}
2018-12-11 19:43:51 +01:00
}
2020-11-06 16:14:31 +01:00
2021-05-12 15:30:56 +02:00
updateTheme ( addon , instances , reset ) {
2020-11-06 16:14:31 +01:00
let path = BDFDB . LibraryRequires . path . join ( dir , addon . filename ) ;
let css = BDFDB . LibraryRequires . fs . readFileSync ( path ) . toString ( ) ;
if ( css ) {
let amount = 0 ;
2021-05-12 15:30:56 +02:00
for ( let i in instances . imports ) {
let input = instances . imports [ i ] ;
2021-01-29 20:57:25 +01:00
let oldValue = input . props . oldValue ;
2021-05-12 15:30:56 +02:00
let newValue = reset ? input . props . defaultValue : input . props . value ;
2020-12-19 19:53:11 +01:00
if ( newValue . toString ( ) != oldValue . toString ( ) ) {
2021-05-12 15:30:56 +02:00
let trueValue = typeof newValue == "string" ? newValue == "true" : newValue ;
2021-01-29 20:57:25 +01:00
let importUrl = input . props . name ;
2021-05-12 15:30:56 +02:00
if ( trueValue ) css = css . replace ( new RegExp ( ` \\ n ${ BDFDB . StringUtils . regEscape ( "/* @import url(" + importUrl + "); */" ) } ` , "g" ) , ` \n @import url( ${ importUrl } ); ` ) ;
2020-12-19 19:53:11 +01:00
else css = css . replace ( new RegExp ( ` \\ n ${ BDFDB . StringUtils . regEscape ( "@import url(" + importUrl + ");" ) } ` , "g" ) , ` \n /* @import url( ${ importUrl } ); */ ` ) ;
2021-05-12 15:30:56 +02:00
input . props . value = trueValue ;
2021-01-29 20:57:25 +01:00
input . props . oldValue = newValue ;
2020-12-19 19:53:11 +01:00
amount ++ ;
}
}
2021-05-12 15:30:56 +02:00
for ( let i in instances . inputs ) {
let input = instances . inputs [ i ] ;
2021-01-29 20:57:25 +01:00
let oldValue = input . props . oldValue ;
2021-05-12 15:30:56 +02:00
let newValue = reset ? input . props . defaultValue : input . props . value ;
2020-11-06 16:14:31 +01:00
if ( newValue && newValue . trim ( ) && newValue != oldValue ) {
2021-01-29 20:57:25 +01:00
let varName = input . props . name ;
2020-12-19 19:53:11 +01:00
css = css . replace ( new RegExp ( ` -- ${ BDFDB . StringUtils . regEscape ( varName ) } ( \\ s*):( \\ s*) ${ BDFDB . StringUtils . regEscape ( oldValue ) } ` , "g" ) , ` -- ${ varName } $ 1: $ 2 ${ newValue } ` ) ;
2021-05-12 15:30:56 +02:00
input . props . value = newValue ;
2021-01-29 20:57:25 +01:00
input . props . oldValue = newValue ;
input . props . placeholder = newValue ;
2020-11-06 16:14:31 +01:00
amount ++ ;
}
}
if ( amount > 0 ) {
2021-05-12 15:30:56 +02:00
BDFDB . ReactUtils . forceUpdate ( BDFDB . ObjectUtils . toArray ( instances . imports ) , BDFDB . ObjectUtils . toArray ( instances . inputs ) ) ;
2020-11-06 16:14:31 +01:00
BDFDB . LibraryRequires . fs . writeFileSync ( path , css ) ;
2021-01-29 20:57:25 +01:00
BDFDB . NotificationUtils . toast ( ` Updated ${ amount } Variable ${ amount == 1 ? "" : "s" } in ' ${ addon . filename } ' ` , { type : "success" } ) ;
2020-11-06 16:14:31 +01:00
}
2021-01-29 20:57:25 +01:00
else BDFDB . NotificationUtils . toast ( ` There are no changed Variables to be updated in ' ${ addon . filename } ' ` , { type : "warning" } ) ;
2020-11-06 16:14:31 +01:00
}
2021-01-29 20:57:25 +01:00
else BDFDB . NotificationUtils . toast ( ` Could not find Theme File ' ${ addon . filename } ' ` , { type : "danger" } ) ;
2020-11-06 16:14:31 +01:00
}
2020-09-19 20:49:33 +02:00
} ;
2020-10-09 21:09:35 +02:00
} ) ( window . BDFDB _Global . PluginUtils . buildPlugin ( config ) ) ;
2020-09-19 20:49:33 +02:00
} ) ( ) ;