Merge pull request #105 from samuelthomas2774/add-theme-config
Save theme configuration when enabled/disabled
This commit is contained in:
commit
f05517a0a4
|
@ -16,6 +16,8 @@ class Theme {
|
|||
|
||||
constructor(themeInternals) {
|
||||
this.__themeInternals = themeInternals;
|
||||
this.hasSettings = this.themeConfig && this.themeConfig.length > 0;
|
||||
this.saveSettings = this.saveSettings.bind(this);
|
||||
this.enable = this.enable.bind(this);
|
||||
this.disable = this.disable.bind(this);
|
||||
}
|
||||
|
@ -37,13 +39,39 @@ class Theme {
|
|||
get css() { return this.__themeInternals.css }
|
||||
get id() { return this.name.toLowerCase().replace(/\s+/g, '-') }
|
||||
|
||||
async saveSettings(newSettings) {
|
||||
if (newSettings) {
|
||||
for (let category of newSettings) {
|
||||
const oldCategory = this.themeConfig.find(c => c.category === category.category);
|
||||
for (let setting of category.settings) {
|
||||
const oldSetting = oldCategory.settings.find(s => s.id === setting.id);
|
||||
if (oldSetting.value === setting.value) continue;
|
||||
oldSetting.value = setting.value;
|
||||
if (this.settingChanged) this.settingChanged(category.category, setting.id, setting.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await FileUtils.writeFile(`${this.themePath}/user.config.json`, JSON.stringify({ enabled: this.enabled, config: this.themeConfig }));
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (this.settingsChanged) this.settingsChanged(this.themeConfig);
|
||||
|
||||
return this.pluginConfig;
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.userConfig.enabled = true;
|
||||
this.saveSettings();
|
||||
DOM.injectTheme(this.css, this.id);
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.userConfig.enabled = false;
|
||||
this.saveSettings();
|
||||
DOM.deleteTheme(this.id);
|
||||
}
|
||||
|
||||
|
@ -68,21 +96,13 @@ export default class extends ContentManager {
|
|||
try {
|
||||
const css = await FileUtils.readFile(paths.mainPath);
|
||||
const instance = new Theme({ configs, info, main, paths: { contentPath: paths.contentPath, dirName: paths.dirName }, css });
|
||||
if (instance.enabled) instance.enable();
|
||||
return instance;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static async loadPlugin(paths, configs, info, main) {
|
||||
const plugin = window.require(paths.mainPath)(Plugin, {}, {});
|
||||
const instance = new plugin({ configs, info, main, paths: { contentPath: paths.contentPath, dirName: paths.dirName } });
|
||||
|
||||
if (instance.enabled) instance.start();
|
||||
return instance;
|
||||
}
|
||||
|
||||
static enableTheme(theme) {
|
||||
theme.enable();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* BetterDiscord Theme Settings Modal Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-plugin-settings-modal" :class="{'bd-edited': changed}">
|
||||
<div class="bd-backdrop" @click="attemptToClose" :class="{'bd-backdrop-out': closing}"></div>
|
||||
<Modal :headerText="theme.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': closing}">
|
||||
<div slot="body" class="bd-plugin-settings-body">
|
||||
<template v-for="category in configCache">
|
||||
<div v-if="category.category === 'default' || !category.type">
|
||||
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
|
||||
</div>
|
||||
<div v-else-if="category.type === 'static'">
|
||||
<div class="bd-form-header">
|
||||
<span class="bd-form-header-text">{{category.category}} static with header</span>
|
||||
</div>
|
||||
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
|
||||
</div>
|
||||
<Drawer v-else-if="category.type === 'drawer'" :label="category.category + ' drawer'">
|
||||
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
|
||||
</Drawer>
|
||||
<div v-else>
|
||||
<PluginSetting v-for="setting in category.settings" :key="setting.id" :setting="setting" :change="settingChange" :changed="setting.changed"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div slot="footer" class="bd-footer-alert" :class ="{'bd-active': changed, 'bd-warn': warnclose}">
|
||||
<div class="bd-footer-alert-text">Unsaved changes</div>
|
||||
<div class="bd-button bd-reset-button bd-tp" :class="{'bd-disabled': saving}" @click="resetSettings">Reset</div>
|
||||
<div class="bd-button bd-ok" :class="{'bd-disabled': saving}" @click="saveSettings">
|
||||
<div v-if="saving" class="bd-spinner-7"></div>
|
||||
<template v-else>Save Changes</template>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { Modal } from '../common';
|
||||
import PluginSetting from './pluginsetting/PluginSetting.vue';
|
||||
import Drawer from '../common/Drawer.vue';
|
||||
|
||||
export default {
|
||||
props: ['theme', 'close'],
|
||||
data() {
|
||||
return {
|
||||
changed: false,
|
||||
warnclose: false,
|
||||
configCache: [],
|
||||
closing: false,
|
||||
saving: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Modal,
|
||||
PluginSetting,
|
||||
Drawer
|
||||
},
|
||||
methods: {
|
||||
checkForChanges() {
|
||||
let changed = false;
|
||||
for (let category of this.configCache) {
|
||||
const cat = this.theme.themeConfig.find(c => c.category === category.category);
|
||||
for (let setting of category.settings) {
|
||||
if (cat.settings.find(s => s.id === setting.id).value !== setting.value) {
|
||||
changed = true;
|
||||
setting.changed = true;
|
||||
} else {
|
||||
setting.changed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
},
|
||||
settingChange(settingId, newValue) {
|
||||
for (let category of this.configCache) {
|
||||
const found = category.settings.find(s => s.id === settingId);
|
||||
if (found) {
|
||||
found.value = newValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.changed = this.checkForChanges();
|
||||
this.$forceUpdate();
|
||||
},
|
||||
async saveSettings() {
|
||||
if (this.saving) return;
|
||||
this.saving = true;
|
||||
try {
|
||||
await this.theme.saveSettings(this.configCache);
|
||||
this.configCache = JSON.parse(JSON.stringify(this.theme.themeConfig));
|
||||
this.changed = false;
|
||||
} catch (err) {
|
||||
// TODO Display error that settings failed to save
|
||||
console.log(err);
|
||||
}
|
||||
this.saving = false;
|
||||
},
|
||||
resetSettings() {
|
||||
if (this.saving) return;
|
||||
this.configCache = JSON.parse(JSON.stringify(this.theme.themeConfig));
|
||||
this.changed = false;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
attemptToClose(e) {
|
||||
if (!this.changed) {
|
||||
this.closing = true;
|
||||
setTimeout(() => {
|
||||
this.close();
|
||||
}, 200);
|
||||
return;
|
||||
}
|
||||
this.warnclose = true;
|
||||
setTimeout(() => {
|
||||
this.warnclose = false;
|
||||
}, 400);
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.configCache = JSON.parse(JSON.stringify(this.theme.themeConfig));
|
||||
console.log(this.configCache);
|
||||
this.changed = this.checkForChanges();
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -32,6 +32,7 @@
|
|||
<div class="bd-spinner-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<ThemeSettingsModal v-if="settingsOpen !== null" :theme="settingsOpen" :close="closeSettings" />
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
|
@ -40,6 +41,7 @@
|
|||
import { ThemeManager } from 'modules';
|
||||
import { SettingsWrapper } from './';
|
||||
import { MiRefresh } from '../common';
|
||||
import ThemeSettingsModal from './ThemeSettingsModal.vue';
|
||||
import ThemeCard from './ThemeCard.vue';
|
||||
|
||||
export default {
|
||||
|
@ -52,6 +54,7 @@
|
|||
},
|
||||
components: {
|
||||
SettingsWrapper, ThemeCard,
|
||||
ThemeSettingsModal,
|
||||
MiRefresh
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -6,5 +6,38 @@
|
|||
"description": "Example Theme 1 Description",
|
||||
"icon": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg=="
|
||||
},
|
||||
"main": "index.css"
|
||||
"main": "index.css",
|
||||
"defaultConfig": [
|
||||
{
|
||||
"category": "default",
|
||||
"settings": [
|
||||
{
|
||||
"id": "default-0",
|
||||
"type": "text",
|
||||
"value": null,
|
||||
"text": "Test setting #1",
|
||||
"hint": "Just some test settings to test the settings panel for themes"
|
||||
},
|
||||
{
|
||||
"id": "default-1",
|
||||
"type": "bool",
|
||||
"value": true,
|
||||
"text": "Work properly",
|
||||
"hint": "Just some test settings to test the settings panel for themes"
|
||||
},
|
||||
{
|
||||
"id": "default-2",
|
||||
"type": "radio",
|
||||
"value": "opt1",
|
||||
"text": "Test Radio Setting",
|
||||
"hint": "Just some test settings to test the settings panel for themes",
|
||||
"options": [
|
||||
{ "value": 1, "text": "Option 1" },
|
||||
{ "value": 2, "text": "Option 2" },
|
||||
{ "value": 3, "text": "Option 3" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue