Refactor settings menu

Adds support for dynamically adding items
This commit is contained in:
Samuel Elliott 2018-03-07 20:19:02 +00:00
parent 0bbd7b506a
commit 5e259f50f8
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
6 changed files with 129 additions and 44 deletions

View File

@ -18,7 +18,23 @@ import path from 'path';
export default new class Settings {
constructor() {
this.settings = [];
this.settings = defaultSettings.map(_set => {
const set = new SettingsSet(_set);
set.on('setting-updated', event => {
const { category, setting, value, old_value } = event;
Logger.log('Settings', `${set.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`);
Events.emit('setting-updated', event);
Events.emit(`setting-updated-${set.id}_${category.id}_${setting.id}`, event);
});
set.on('settings-updated', async (event) => {
await this.saveSettings();
Events.emit('settings-updated', event);
});
return set;
});
}
async loadSettings() {
@ -29,22 +45,12 @@ export default new class Settings {
const user_config = await FileUtils.readJsonFromFile(settingsPath);
const { settings, scss, css, css_editor_files, scss_error, css_editor_bounds } = user_config;
this.settings = defaultSettings.map(set => {
const newSet = new SettingsSet(set);
newSet.merge(settings.find(s => s.id === newSet.id));
newSet.setSaved();
newSet.on('setting-updated', event => {
const { category, setting, value, old_value } = event;
Logger.log('Settings', `${newSet.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`);
Events.emit('setting-updated', event);
Events.emit(`setting-updated-${newSet.id}_${category.id}_${setting.id}`, event);
});
newSet.on('settings-updated', async (event) => {
await this.saveSettings();
Events.emit('settings-updated', event);
});
return newSet;
});
for (let set of this.settings) {
const newSet = settings.find(s => s.id === set.id);
if (!newSet) continue;
set.merge(newSet);
set.setSaved();
}
CssEditor.setState(scss, css, css_editor_files, scss_error);
CssEditor.editor_bounds = css_editor_bounds || {};

61
client/src/ui/bdmenu.js Normal file
View File

@ -0,0 +1,61 @@
/**
* BetterDiscord Menu Module
* 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.
*/
import { Utils } from 'common';
let items = 0;
const BdMenuItems = new class {
constructor() {
window.bdmenu = this;
this.items = [];
this.addSettingsSet('Internal', 'core', 'Core');
this.addSettingsSet('Internal', 'ui', 'UI');
this.addSettingsSet('Internal', 'emotes', 'Emotes');
this.add({category: 'Internal', contentid: 'css', text: 'CSS Editor'});
this.add({category: 'External', contentid: 'plugins', text: 'Plugins'});
this.add({category: 'External', contentid: 'themes', text: 'Themes'});
}
add(item) {
item.id = items++;
item.contentid = item.contentid || (items++ + '');
item.active = false;
item.hidden = item.hidden || false;
item._type = item._type || 'button';
this.items.push(item);
return item;
}
addSettingsSet(category, set, text) {
return this.add({
category, set,
text: text || set.text
});
}
addVueComponent(category, text, component) {
return this.add({
category, text, component
});
}
remove(item) {
Utils.removeFromArray(this.items, item);
}
};
export { BdMenuItems };

View File

@ -86,4 +86,5 @@ export default class {
return vueInstance;
}
}

View File

@ -16,7 +16,10 @@
<MiClose size="17"/>
<span class="bd-x-text">ESC</span>
</div>
<SidebarItem v-for="item in sidebarItems" :item="item" :key="item.id" :onClick="itemOnClick" />
<template v-for="(category, text) in sidebar">
<SidebarItem :item="{text, type: 'header'}" />
<SidebarItem v-for="item in category" :item="item" :key="item.id" :onClick="itemOnClick" />
</template>
</Sidebar>
<div slot="sidebarfooter" class="bd-info">
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
@ -31,19 +34,21 @@
</div>
</div>
<ContentColumn slot="content">
<div v-for="set in Settings.settings" v-if="!set.hidden && activeContent(set.id) || animatingContent(set.id)" :class="{active: activeContent(set.id), animating: animatingContent(set.id)}">
<SettingsWrapper :headertext="set.headertext">
<SettingsPanel :settings="set" :schemes="set.schemes" />
<div v-for="item in sidebarItems" v-if="activeContent(item.contentid) || animatingContent(item.contentid)" :class="{active: activeContent(item.contentid), animating: animatingContent(item.contentid)}">
<template v-if="item.component">
<component :is="item.component" :SettingsWrapper="SettingsWrapper" />
</template>
<SettingsWrapper v-if="typeof item.set === 'string'" :headertext="Settings.getSet(item.set).headertext">
<SettingsPanel :settings="Settings.getSet(item.set)" :schemes="Settings.getSet(item.set).schemes" />
</SettingsWrapper>
</div>
<div v-if="activeContent('css') || animatingContent('css')" :class="{active: activeContent('css'), animating: animatingContent('css')}">
<CssEditorView />
</div>
<div v-if="activeContent('plugins') || animatingContent('plugins')" :class="{active: activeContent('plugins'), animating: animatingContent('plugins')}">
<PluginsView />
</div>
<div v-if="activeContent('themes') || animatingContent('themes')" :class="{active: activeContent('themes'), animating: animatingContent('themes')}">
<ThemesView />
<SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext">
<SettingsPanel :settings="item.set" :schemes="item.set.schemes" />
</SettingsWrapper>
<CssEditorView v-if="item.contentid === 'css'" />
<PluginsView v-if="item.contentid === 'plugins'" />
<ThemesView v-if="item.contentid === 'themes'" />
</div>
</ContentColumn>
</SidebarView>
@ -53,32 +58,22 @@
// Imports
import { shell } from 'electron';
import { Settings } from 'modules';
import { BdMenuItems } from 'ui';
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView } from './bd';
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
// Constants
const sidebarItems = [
{ text: 'Internal', _type: 'header' },
{ id: 0, contentid: "core", text: 'Core', active: false, _type: 'button' },
{ id: 1, contentid: "ui", text: 'UI', active: false, _type: 'button' },
{ id: 2, contentid: "emotes", text: 'Emotes', active: false, _type: 'button' },
{ id: 3, contentid: "css", text: 'CSS Editor', active: false, _type: 'button' },
{ text: 'External', _type: 'header' },
{ id: 4, contentid: "plugins", text: 'Plugins', active: false, _type: 'button' },
{ id: 5, contentid: "themes", text: 'Themes', active: false, _type: 'button' }
];
export default {
data() {
return {
sidebarItems,
BdMenuItems,
activeIndex: -1,
lastActiveIndex: -1,
animating: false,
first: true,
Settings,
timeout: null
timeout: null,
SettingsWrapper
}
},
props: ['active', 'close'],
@ -87,6 +82,20 @@
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView,
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
},
computed: {
sidebarItems() {
return this.BdMenuItems.items;
},
sidebar() {
const categories = {};
for (let item of this.sidebarItems) {
if (item.hidden) continue;
const category = categories[item.category] || (categories[item.category] = []);
category.push(item);
}
return categories;
}
},
methods: {
itemOnClick(id) {
if (this.animating || id === this.activeIndex) return;

View File

@ -1,5 +1,6 @@
export { default as DOM } from './dom';
export { default as BdUI } from './bdui';
export { default as VueInjector } from './vueinjector';
export * from './bdmenu';
export { default as Modals } from './modals';
export { default as ProfileBadges } from './profilebadges';

View File

@ -159,6 +159,13 @@ export class Utils {
return object;
}
static removeFromArray(array, item) {
let index;
while ((index = array.indexOf(item)) > -1)
array.splice(index, 1);
return array;
}
}
export class FileUtils {