Add theme configuration and saving
This commit is contained in:
parent
f71d79fd90
commit
08b791e547
|
@ -16,6 +16,8 @@ class Theme {
|
||||||
|
|
||||||
constructor(themeInternals) {
|
constructor(themeInternals) {
|
||||||
this.__themeInternals = 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.enable = this.enable.bind(this);
|
||||||
this.disable = this.disable.bind(this);
|
this.disable = this.disable.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -37,13 +39,39 @@ class Theme {
|
||||||
get css() { return this.__themeInternals.css }
|
get css() { return this.__themeInternals.css }
|
||||||
get id() { return this.name.toLowerCase().replace(/\s+/g, '-') }
|
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() {
|
enable() {
|
||||||
this.userConfig.enabled = true;
|
this.userConfig.enabled = true;
|
||||||
|
this.saveSettings();
|
||||||
DOM.injectTheme(this.css, this.id);
|
DOM.injectTheme(this.css, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
disable() {
|
disable() {
|
||||||
this.userConfig.enabled = false;
|
this.userConfig.enabled = false;
|
||||||
|
this.saveSettings();
|
||||||
DOM.deleteTheme(this.id);
|
DOM.deleteTheme(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,15 +102,6 @@ export default class extends ContentManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
static enableTheme(theme) {
|
||||||
theme.enable();
|
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 class="bd-spinner-2"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ThemeSettingsModal v-if="settingsOpen !== null" :theme="settingsOpen" :close="closeSettings" />
|
||||||
</SettingsWrapper>
|
</SettingsWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
import { ThemeManager } from 'modules';
|
import { ThemeManager } from 'modules';
|
||||||
import { SettingsWrapper } from './';
|
import { SettingsWrapper } from './';
|
||||||
import { MiRefresh } from '../common';
|
import { MiRefresh } from '../common';
|
||||||
|
import ThemeSettingsModal from './ThemeSettingsModal.vue';
|
||||||
import ThemeCard from './ThemeCard.vue';
|
import ThemeCard from './ThemeCard.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SettingsWrapper, ThemeCard,
|
SettingsWrapper, ThemeCard,
|
||||||
|
ThemeSettingsModal,
|
||||||
MiRefresh
|
MiRefresh
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -6,5 +6,38 @@
|
||||||
"description": "Example Theme 1 Description",
|
"description": "Example Theme 1 Description",
|
||||||
"icon": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg=="
|
"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