commit
7899312e73
|
@ -9,6 +9,10 @@
|
|||
*/
|
||||
|
||||
import BuiltinModule from './BuiltinModule';
|
||||
import { WebpackModules, ReactComponents, MonkeyPatch, Patcher } from 'modules';
|
||||
import { VueInjector, Reflection } from 'ui';
|
||||
import E2EEComponent from './E2EEComponent.vue';
|
||||
import aes256 from 'aes256';
|
||||
|
||||
export default new class E2EE extends BuiltinModule {
|
||||
|
||||
|
@ -16,12 +20,25 @@ export default new class E2EE extends BuiltinModule {
|
|||
return ['security', 'default', 'e2ee'];
|
||||
}
|
||||
|
||||
enabled(e) {
|
||||
|
||||
async enabled(e) {
|
||||
const ctaComponent = await ReactComponents.getComponent('ChannelTextArea');
|
||||
MonkeyPatch('BD:E2EE', ctaComponent.component.prototype).after('render', this.render);
|
||||
MonkeyPatch('BD:E2EE', ctaComponent.component.prototype).before('handleSubmit', this.handleSubmit);
|
||||
}
|
||||
|
||||
render(component, args, retVal) {
|
||||
if (!(retVal.props.children instanceof Array)) retVal.props.children = [retVal.props.children];
|
||||
const inner = retVal.props.children.find(child => child.props.className && child.props.className.includes('inner'));
|
||||
|
||||
inner.props.children.splice(0, 0, VueInjector.createReactElement(E2EEComponent, {}, true));
|
||||
}
|
||||
|
||||
handleSubmit(component, args, retVal) {
|
||||
component.props.value = aes256.encrypt('randomkey', component.props.value);
|
||||
}
|
||||
|
||||
disabled(e) {
|
||||
|
||||
for (const patch of Patcher.getPatchesByCaller('BD:E2EE')) patch.unpatch();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* BetterDiscord E2EE 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-e2eeTaContainer">
|
||||
<div class="bd-e2eeTaBtn bd-e2eeLock">
|
||||
<MiLock v-tooltip="'E2EE'" />
|
||||
</div>
|
||||
<div class="bd-taDivider"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { MiLock } from '../ui/components/common/MaterialIcon';
|
||||
export default {
|
||||
components: { MiLock },
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
|
@ -2,6 +2,7 @@ import { default as EmoteModule } from './EmoteModule';
|
|||
import { default as ReactDevtoolsModule } from './ReactDevtoolsModule';
|
||||
import { default as VueDevtoolsModule } from './VueDevToolsModule';
|
||||
import { default as TrackingProtection } from './TrackingProtection';
|
||||
import { default as E2EE } from './E2EE';
|
||||
|
||||
export default class {
|
||||
static initAll() {
|
||||
|
@ -9,5 +10,6 @@ export default class {
|
|||
ReactDevtoolsModule.init();
|
||||
VueDevtoolsModule.init();
|
||||
TrackingProtection.init();
|
||||
E2EE.init();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,10 +171,9 @@
|
|||
"type": "drawer",
|
||||
"settings": [
|
||||
{
|
||||
"id": "kvp0",
|
||||
"type": "kvp",
|
||||
"text": "",
|
||||
"value": { "key": "kvpKey", "value": "kvpValue" }
|
||||
"id": "e2ekvps",
|
||||
"type": [ "securekvp" ],
|
||||
"value": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import { DOM, Reflection } from 'ui';
|
||||
import { DOM, Reflection, Modals } from 'ui';
|
||||
import { Utils, Filters, ClientLogger as Logger } from 'common';
|
||||
import { MonkeyPatch } from './patcher';
|
||||
import { WebpackModules } from './webpackmodules';
|
||||
|
@ -501,4 +501,30 @@ export class ReactAutoPatcher {
|
|||
|
||||
this.UserPopout.forceUpdateAll();
|
||||
}
|
||||
|
||||
static async patchUploadArea() {
|
||||
const selector = '.' + WebpackModules.getClassName('uploadArea');
|
||||
this.UploadArea = await ReactComponents.getComponent('UploadArea', {selector});
|
||||
|
||||
const reflect = Reflection(selector);
|
||||
const stateNode = reflect.getComponentStateNode(this.UploadArea);
|
||||
const callback = function(e) {
|
||||
if (!e.dataTransfer.files.length || !e.dataTransfer.files[0].name.endsWith('.bd')) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
stateNode.clearDragging();
|
||||
Modals.confirm("Function not ready", `You tried to install "${e.dataTransfer.files[0].path}", but installing .bd files isn't ready yet.`)
|
||||
// Possibly something like Events.emit('install-file', e.dataTransfer.files[0]);
|
||||
};
|
||||
|
||||
// Remove their handler, add ours, then readd theirs to give ours priority to stop theirs when we get a .bd file.
|
||||
reflect.element.removeEventListener('drop', stateNode.handleDrop);
|
||||
reflect.element.addEventListener('drop', callback);
|
||||
reflect.element.addEventListener('drop', stateNode.handleDrop);
|
||||
|
||||
this.unpatchUploadArea = function() {
|
||||
reflect.element.removeEventListener('drop', callback);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,9 @@ import KeybindSetting from './types/keybind';
|
|||
import FileSetting from './types/file';
|
||||
import GuildSetting from './types/guild';
|
||||
import ArraySetting from './types/array';
|
||||
import CollectionSetting from './types/collection';
|
||||
import KvpSetting from './types/kvp';
|
||||
import SecureKvpSetting from './types/securekvp';
|
||||
import CustomSetting from './types/custom';
|
||||
|
||||
export default class Setting {
|
||||
|
@ -27,6 +29,7 @@ export default class Setting {
|
|||
constructor(args, ...merge) {
|
||||
args = args.args || args;
|
||||
|
||||
if (args.type instanceof Array) args.subtype = args.type[0], args.type = 'collection';
|
||||
if (args.type === 'color') args.type = 'colour';
|
||||
|
||||
if (args.type === 'bool') return new BoolSetting(args, ...merge);
|
||||
|
@ -40,8 +43,10 @@ export default class Setting {
|
|||
else if (args.type === 'file') return new FileSetting(args, ...merge);
|
||||
else if (args.type === 'guild') return new GuildSetting(args, ...merge);
|
||||
else if (args.type === 'array') return new ArraySetting(args, ...merge);
|
||||
else if (args.type === 'custom') return new CustomSetting(args, ...merge);
|
||||
else if (args.type === 'collection') return new CollectionSetting(args, ...merge);
|
||||
else if (args.type === 'kvp') return new KvpSetting(args, ...merge);
|
||||
else if (args.type === 'securekvp') return new SecureKvpSetting(args, ...merge);
|
||||
else if (args.type === 'custom') return new CustomSetting(args, ...merge);
|
||||
else throw {message: `Setting type ${args.type} unknown`};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* BetterDiscord Collection Setting Struct
|
||||
* 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';
|
||||
import ArraySetting from './array';
|
||||
import Setting from '../setting';
|
||||
|
||||
export default class CollectionSetting extends ArraySetting {
|
||||
|
||||
constructor(args, ...merge) {
|
||||
// The ArraySetting constructor will call createItem which requires this to be set
|
||||
if (!(args.setting instanceof Setting)) args.setting = new Setting(args.setting || {type: args.subtype});
|
||||
|
||||
super(args, ...merge);
|
||||
}
|
||||
|
||||
get setting() {
|
||||
return this.args.setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new setting for this collection setting.
|
||||
* @param {Setting} item Values to merge into the new setting (optional)
|
||||
* @return {Setting} The new set
|
||||
*/
|
||||
createItem(item) {
|
||||
if (item instanceof Setting)
|
||||
return item;
|
||||
|
||||
const merge = [...arguments].filter(a => a);
|
||||
const setting = this.setting.clone(...merge);
|
||||
setting.args.id = item ? item.args ? item.args.id : item.id : Math.random();
|
||||
|
||||
setting.setSaved();
|
||||
setting.on('settings-updated', async event => {
|
||||
await this.emit('item-updated', { item: setting, event, updatedSettings: event.updatedSettings });
|
||||
if (event.args.updating_array !== this) await this.updateValue();
|
||||
});
|
||||
return setting;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,4 +10,5 @@ export { default as FileSetting } from './file';
|
|||
export { default as GuildSetting } from './guild';
|
||||
export { default as ArraySetting } from './array';
|
||||
export { default as KvpSetting } from './kvp';
|
||||
export { default as CollectionSetting } from './kvp';
|
||||
export { default as CustomSetting } from './custom';
|
||||
|
|
|
@ -16,6 +16,6 @@ export default class KvpSetting extends Setting {
|
|||
* The value to use when the setting doesn't have a value.
|
||||
*/
|
||||
get defaultValue() {
|
||||
return { key: 'Channel ID', value: 'Encryption Key' };
|
||||
return { key: 'Key', value: 'Value' };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* BetterDiscord Secure Key Value Pair Setting Struct
|
||||
* 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 Kvp from './kvp';
|
||||
|
||||
export default class SecureKvpSetting extends Kvp {
|
||||
/**
|
||||
* The value to use when the setting doesn't have a value.
|
||||
*/
|
||||
get defaultValue() {
|
||||
return { key: 'Key', value: '**********' };
|
||||
}
|
||||
}
|
|
@ -43,9 +43,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.bd-hide-button {
|
||||
transition: opacity 0.4s ease-out;
|
||||
opacity: 0;
|
||||
|
||||
&.bd-active {
|
||||
transition-timing-function: ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
&.bd-active {
|
||||
background: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.bd-active,
|
||||
&.bd-hide-button {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
|
||||
.bd-settings-button-btn {
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
.bd-formCollection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
div:first-child {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.bd-collectionItem {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
margin-top: 5px;
|
||||
|
||||
.bd-removeCollectionItem {
|
||||
width: 20px;
|
||||
flex: 0 1 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
margin-bottom: 30px;
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
fill: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-newCollectionItem {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-self: flex-end;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 2px;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
fill: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
.bd-e2eeTaContainer {
|
||||
display: flex;
|
||||
|
||||
.bd-e2eeTaBtn {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: row;
|
||||
cursor: pointer;
|
||||
|
||||
&.bd-e2eeLock {
|
||||
fill: #cc3e3e;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-taDivider {
|
||||
background-color: hsla(0,0%,100%,.1);
|
||||
box-sizing: border-box;
|
||||
height: 80%;
|
||||
position: relative;
|
||||
top: 10%;
|
||||
width: 1px;
|
||||
}
|
||||
}
|
|
@ -8,3 +8,5 @@
|
|||
@import './updater.scss';
|
||||
@import './window-preferences';
|
||||
@import './kvp';
|
||||
@import './collection';
|
||||
@import './e2ee';
|
||||
|
|
|
@ -122,6 +122,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.bd-stop .bd-sidebar-region {
|
||||
z-index: 3004;
|
||||
}
|
||||
&.bd-stop .bd-content-region {
|
||||
z-index: 3003;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
[class*="guildsWrapper-"] {
|
||||
padding-top: 49px !important;
|
||||
|
||||
.platform-osx & {
|
||||
body:not(.bd-hide-button) {
|
||||
[class*="guildsWrapper-"] {
|
||||
padding-top: 49px !important;
|
||||
}
|
||||
.platform-osx [class*="guildsWrapper-"] {
|
||||
margin-top: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
[class*="guildsWrapper-"] + [class*="flex"] {
|
||||
border-radius: 0 0 0 5px;
|
||||
}
|
||||
[class*="guildsWrapper-"] + [class*="flex"] {
|
||||
border-radius: 0 0 0 5px;
|
||||
}
|
||||
|
||||
[class*="unreadMentionsIndicatorTop-"] {
|
||||
top: 49px;
|
||||
|
||||
.platform-osx & {
|
||||
[class*="unreadMentionsIndicatorTop-"] {
|
||||
top: 49px;
|
||||
}
|
||||
.platform-osx [class*="unreadMentionsIndicatorTop-"] {
|
||||
top: 50px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,27 +5,28 @@
|
|||
flex-grow: 1;
|
||||
backface-visibility: hidden;
|
||||
|
||||
> div {
|
||||
> * {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
> div:not(.active) {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
left: 310px;
|
||||
right: 0;
|
||||
// width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-content {
|
||||
animation: bd-fade-in .4s forwards;
|
||||
|
||||
.animating {
|
||||
animation: bd-fade-out .4s forwards;
|
||||
&.bd-contentcolumn-enter-active,
|
||||
&.bd-contentcolumn-leave-active {
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
&.bd-contentcolumn-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.bd-contentcolumn-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.bd-contentcolumn-leave-active {
|
||||
position: absolute;
|
||||
width: 590px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import { Events, DiscordApi } from 'modules';
|
||||
import { Events, DiscordApi, Settings } from 'modules';
|
||||
import { remote } from 'electron';
|
||||
import DOM from './dom';
|
||||
import Vue from './vue';
|
||||
|
@ -17,6 +17,13 @@ import { BdSettingsWrapper, BdModals, BdToasts } from './components';
|
|||
export default class {
|
||||
|
||||
static initUiEvents() {
|
||||
const hideButtonSetting = Settings.getSetting('ui', 'default', 'hide-button');
|
||||
hideButtonSetting.on('setting-updated', event => {
|
||||
if (event.value) document.body.classList.add('bd-hide-button');
|
||||
else document.body.classList.remove('bd-hide-button');
|
||||
});
|
||||
if (hideButtonSetting.value) document.body.classList.add('bd-hide-button');
|
||||
|
||||
this.pathCache = {
|
||||
isDm: null,
|
||||
server: DiscordApi.currentGuild,
|
||||
|
@ -46,22 +53,16 @@ export default class {
|
|||
DOM.createElement('div', null, 'bd-toasts').appendTo(DOM.bdToasts);
|
||||
DOM.createElement('bd-tooltips').appendTo(DOM.bdBody);
|
||||
|
||||
this.toasts = new Vue({
|
||||
el: '#bd-toasts',
|
||||
components: { BdToasts },
|
||||
template: '<BdToasts />'
|
||||
this.toasts = new (Vue.extend(BdToasts))({
|
||||
el: '#bd-toasts'
|
||||
});
|
||||
|
||||
this.modals = new Vue({
|
||||
el: '#bd-modals',
|
||||
components: { BdModals },
|
||||
template: '<BdModals />'
|
||||
this.modals = new (Vue.extend(BdModals))({
|
||||
el: '#bd-modals'
|
||||
});
|
||||
|
||||
this.vueInstance = new Vue({
|
||||
el: '#bd-settings',
|
||||
components: { BdSettingsWrapper },
|
||||
template: '<BdSettingsWrapper />'
|
||||
this.vueInstance = new (Vue.extend(BdSettingsWrapper))({
|
||||
el: '#bd-settings'
|
||||
});
|
||||
|
||||
return this.vueInstance;
|
||||
|
|
|
@ -29,8 +29,8 @@ export default class ClassNormaliser extends Module {
|
|||
shouldIgnore(value) {
|
||||
if (!isNaN(value)) return true;
|
||||
if (value.endsWith('px') || value.endsWith('ch') || value.endsWith('em') || value.endsWith('ms')) return true;
|
||||
if (value.startsWith('rgba')) return true;
|
||||
if (value.includes('calc(')) return true;
|
||||
if (value.startsWith('#') && (value.length == 7 || value.length == 4)) return true;
|
||||
if (value.includes('calc(') || value.includes('rgba')) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-settings" :class="{active: active, 'bd-settings-out': activeIndex === -1 && lastActiveIndex >= 0}" @keyup="$emit('close')">
|
||||
<SidebarView :contentVisible="this.activeIndex >= 0 || this.lastActiveIndex >= 0" :animating="this.animating" :class="{'bd-stop': !first}">
|
||||
<div class="bd-settings" :class="{active, 'bd-settings-out': !item && animating}" @keyup="$emit('close')">
|
||||
<SidebarView :contentVisible="item" :animating="animating" :class="{'bd-stop': item}">
|
||||
<Sidebar slot="sidebar">
|
||||
<div class="bd-settings-x" @click="$emit('close')">
|
||||
<MiClose size="17"/>
|
||||
|
@ -18,9 +18,10 @@
|
|||
</div>
|
||||
<template v-for="(category, text) in sidebar">
|
||||
<SidebarItem :item="{text, type: 'header'}" />
|
||||
<SidebarItem v-for="item in category" :item="item" :key="item.id" @click="itemOnClick(item.id)" />
|
||||
<SidebarItem v-for="i in category" :key="i.id" :item="i" :active="item && i.id === item.id" @click="itemOnClick(i.id)" />
|
||||
</template>
|
||||
</Sidebar>
|
||||
|
||||
<div slot="sidebarfooter" class="bd-info">
|
||||
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
|
||||
<div @click="openGithub" v-tooltip="'GitHub'" class="bd-material-button">
|
||||
|
@ -33,25 +34,28 @@
|
|||
<MiWeb size="16" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentColumn slot="content">
|
||||
<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>
|
||||
<transition name="bd-contentcolumn" @before-enter="animating++" @after-enter="animating--" @enter-cancelled="animating--" @before-leave="animating++" @after-leave="animating--" @leave-cancelled="animating--">
|
||||
<div v-if="item" :key="item.id">
|
||||
<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>
|
||||
<SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext">
|
||||
<SettingsPanel :settings="item.set" :schemes="item.set.schemes" />
|
||||
</SettingsWrapper>
|
||||
<SettingsWrapper v-else-if="typeof item.set === 'string'" :headertext="Settings.getSet(item.set).headertext">
|
||||
<SettingsPanel :settings="Settings.getSet(item.set)" :schemes="Settings.getSet(item.set).schemes" />
|
||||
</SettingsWrapper>
|
||||
<SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext">
|
||||
<SettingsPanel :settings="item.set" :schemes="item.set.schemes" />
|
||||
</SettingsWrapper>
|
||||
|
||||
<ConnectivityView v-if="item.contentid === 'connectivity'"/>
|
||||
<CssEditorView v-if="item.contentid === 'css'" />
|
||||
<PluginsView v-if="item.contentid === 'plugins'" />
|
||||
<ThemesView v-if="item.contentid === 'themes'" />
|
||||
<UpdaterView v-if="item.contentid === 'updater'" />
|
||||
</div>
|
||||
<ConnectivityView v-else-if="item.contentid === 'connectivity'" />
|
||||
<CssEditorView v-else-if="item.contentid === 'css'" />
|
||||
<PluginsView v-else-if="item.contentid === 'plugins'" />
|
||||
<ThemesView v-else-if="item.contentid === 'themes'" />
|
||||
<UpdaterView v-else-if="item.contentid === 'updater'" />
|
||||
</div>
|
||||
</transition>
|
||||
</ContentColumn>
|
||||
</SidebarView>
|
||||
</div>
|
||||
|
@ -69,13 +73,10 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
BdMenuItems,
|
||||
activeIndex: -1,
|
||||
lastActiveIndex: -1,
|
||||
animating: false,
|
||||
first: true,
|
||||
animating: 0,
|
||||
item: null,
|
||||
items: BdMenuItems.items,
|
||||
Settings,
|
||||
timeout: null,
|
||||
SettingsWrapper,
|
||||
openMenuHandler: null
|
||||
};
|
||||
|
@ -87,12 +88,9 @@
|
|||
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
|
||||
},
|
||||
computed: {
|
||||
sidebarItems() {
|
||||
return this.BdMenuItems.items;
|
||||
},
|
||||
sidebar() {
|
||||
const categories = {};
|
||||
for (let item of this.sidebarItems) {
|
||||
for (let item of this.items) {
|
||||
if (item.hidden) continue;
|
||||
const category = categories[item.category] || (categories[item.category] = []);
|
||||
category.push(item);
|
||||
|
@ -102,42 +100,10 @@
|
|||
},
|
||||
methods: {
|
||||
itemOnClick(id) {
|
||||
if (this.animating || id === this.activeIndex) return;
|
||||
const activeItem = this.sidebarItems.find(item => item.id === this.activeIndex);
|
||||
if (activeItem) activeItem.active = false;
|
||||
this.sidebarItems.find(item => item.id === id).active = true;
|
||||
this.animating = true;
|
||||
this.lastActiveIndex = this.activeIndex;
|
||||
this.activeIndex = id;
|
||||
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.first = false;
|
||||
this.animating = false;
|
||||
this.lastActiveIndex = -1;
|
||||
this.timeout = null;
|
||||
}, 400);
|
||||
},
|
||||
activeContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
return item && item.id === this.activeIndex;
|
||||
},
|
||||
animatingContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
return item && item.id === this.lastActiveIndex;
|
||||
this.item = this.items.find(item => item.id === id);
|
||||
},
|
||||
closeContent() {
|
||||
if (this.activeIndex >= 0) this.sidebarItems.find(item => item.id === this.activeIndex).active = false;
|
||||
this.first = true;
|
||||
this.lastActiveIndex = this.activeIndex;
|
||||
this.activeIndex = -1;
|
||||
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
this.timeout = setTimeout(() => {
|
||||
this.animating = false;
|
||||
this.lastActiveIndex = -1;
|
||||
this.timeout = null;
|
||||
}, 400);
|
||||
this.item = null;
|
||||
},
|
||||
openGithub() {
|
||||
shell.openExternal('https://github.com/JsSucks/BetterDiscordApp');
|
||||
|
@ -156,7 +122,7 @@
|
|||
}
|
||||
},
|
||||
created() {
|
||||
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.sidebarItems.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
|
||||
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.items.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
|
||||
},
|
||||
destroyed() {
|
||||
if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler);
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-settings-wrapper" :class="[{active: active}, 'platform-' + this.platform]">
|
||||
<div class="bd-settings-button" :class="{'bd-active': active, 'bd-animating': animating}" @click="active = true">
|
||||
<div class="bd-settings-wrapper" :class="[{active}, 'platform-' + this.platform]">
|
||||
<div class="bd-settings-button" :class="{'bd-active': active, 'bd-animating': animating, 'bd-hide-button': hideButton}" @click="active = true">
|
||||
<div v-if="updating === 0" v-tooltip.right="'Checking for updates'" class="bd-settings-button-btn bd-loading"></div>
|
||||
<div v-else-if="updating === 2" v-tooltip.right="'Updates available!'" class="bd-settings-button-btn bd-updates"></div>
|
||||
<div v-else class="bd-settings-button-btn" :class="[{'bd-loading': !loaded}]"></div>
|
||||
|
@ -36,7 +36,9 @@
|
|||
timeout: null,
|
||||
platform: process.platform,
|
||||
eventHandlers: {},
|
||||
keybindHandler: null
|
||||
keybindHandler: null,
|
||||
hideButton: false,
|
||||
hideButtonToggleHandler: null
|
||||
};
|
||||
},
|
||||
components: {
|
||||
|
@ -80,6 +82,10 @@
|
|||
|
||||
const menuKeybind = Settings.getSetting('core', 'default', 'menu-keybind');
|
||||
menuKeybind.on('keybind-activated', this.keybindHandler = () => this.active = !this.active);
|
||||
|
||||
const hideButtonSetting = Settings.getSetting('ui', 'default', 'hide-button');
|
||||
hideButtonSetting.on('setting-updated', this.hideButtonToggleHandler = event => this.hideButton = event.value);
|
||||
this.hideButton = hideButtonSetting.value;
|
||||
},
|
||||
destroyed() {
|
||||
for (let event in this.eventHandlers) Events.off(event, this.eventHandlers[event]);
|
||||
|
@ -89,7 +95,12 @@
|
|||
|
||||
if (this.keybindHandler) {
|
||||
const menuKeybind = Settings.getSetting('core', 'default', 'menu-keybind');
|
||||
menuKeybind.removeListener('keybind-activated', this.keybindHandler = () => this.active = !this.active);
|
||||
menuKeybind.removeListener('keybind-activated', this.keybindHandler);
|
||||
}
|
||||
|
||||
if (this.hideButtonToggleHandler) {
|
||||
const hideButtonSetting = Settings.getSetting('ui', 'default', 'hide-button');
|
||||
hideButtonSetting.removeListener('setting-updated', this.hideButtonToggleHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* BetterDiscord Collection Setting 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-formCollection">
|
||||
<div v-for="s in setting.items" class="bd-collectionItem">
|
||||
<Setting :setting="s" :key="s.id" />
|
||||
<div class="bd-removeCollectionItem" @click="removeItem(s)"><MiMinus/></div>
|
||||
</div>
|
||||
<div class="bd-newCollectionItem" @click="addItem"><MiPlus/></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Setting from './Setting.vue';
|
||||
import { MiMinus, MiPlus } from '../../common';
|
||||
|
||||
export default {
|
||||
props: ['setting'],
|
||||
components: {
|
||||
MiMinus, MiPlus
|
||||
},
|
||||
methods: {
|
||||
removeItem(item) {
|
||||
this.setting.removeItem(item);
|
||||
},
|
||||
addItem() {
|
||||
this.setting.addItem();
|
||||
}
|
||||
},
|
||||
beforeCreate() {
|
||||
// https://vuejs.org/v2/guide/components.html#Circular-References-Between-Components
|
||||
this.$options.components.Setting = Setting;
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -12,12 +12,11 @@
|
|||
<div class="bd-formKvp">
|
||||
<div class="bd-formKvpDetails">
|
||||
<div class="bd-inputWrapper">
|
||||
<input type="text" class="bd-textInput" :value="setting.value.key" />
|
||||
<input type="text" class="bd-textInput" :value="setting.value.key" @keyup.stop @input="keyChange"/>
|
||||
</div>
|
||||
<div class="bd-inputWrapper">
|
||||
<input type="text" class="bd-textInput" :value="setting.value.value" />
|
||||
<input type="text" class="bd-textInput" :value="setting.value.value" @keyup.stop @input="valueChange"/>
|
||||
</div>
|
||||
<!-- using a text field is temporary -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -25,7 +24,13 @@
|
|||
<script>
|
||||
export default {
|
||||
props: ['setting'],
|
||||
methods: {},
|
||||
mounted() {console.log('setting', this.setting)}
|
||||
methods: {
|
||||
keyChange(e) {
|
||||
this.setting.value = { key: e.target.value, value: this.setting.value.value }
|
||||
},
|
||||
valueChange(e) {
|
||||
this.setting.value = { key: this.setting.value.key, value: e.target.value }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* BetterDiscord Setting Secure Key Value Pair 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-formKvp">
|
||||
<div class="bd-formKvpDetails">
|
||||
<div class="bd-inputWrapper">
|
||||
<input type="text" class="bd-textInput" :value="setting.value.key" @keyup.stop="keyUpKey" @input="keyChange" />
|
||||
</div>
|
||||
<div class="bd-inputWrapper">
|
||||
<input type="password" class="bd-textInput" :value="setting.value.value" @keyup.stop="keyUpValue" @blur="valueBlur" @input="valueChange" ref="valueInput" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import aes256 from 'aes256';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
masterKey: 'temporarymasterkey',
|
||||
valueChanged: false
|
||||
}
|
||||
},
|
||||
props: ['setting'],
|
||||
methods: {
|
||||
keyChange(e) {
|
||||
this.setting.value = { key: e.target.value, value: this.setting.value.value }
|
||||
},
|
||||
valueChange(e) {
|
||||
this.valueChanged = true;
|
||||
},
|
||||
valueBlur(e) {
|
||||
if (!this.valueChanged) return;
|
||||
const value = aes256.encrypt(this.masterKey, e.target.value);
|
||||
this.setting.value = { key: this.setting.value.key, value }
|
||||
this.valueChanged = false;
|
||||
},
|
||||
keyUpKey(e) {
|
||||
if (e.key !== 'Enter') return;
|
||||
this.$refs.valueInput.focus();
|
||||
},
|
||||
keyUpValue(e) {
|
||||
if (e.key !== 'Enter') return;
|
||||
e.target.blur();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -11,19 +11,21 @@
|
|||
<template>
|
||||
<div class="bd-form-item" :class="{'bd-form-item-changed': setting.changed, 'bd-disabled': disabled, 'bd-form-item-noheader': !setting.text, 'bd-form-item-fullwidth': setting.fullwidth}">
|
||||
<BoolSetting v-if="setting.type === 'bool'" :setting="setting" />
|
||||
<StringSetting v-if="setting.type === 'text' && !setting.multiline" :setting="setting" />
|
||||
<MultilineTextSetting v-if="setting.type === 'text' && setting.multiline" :setting="setting" />
|
||||
<NumberSetting v-if="setting.type === 'number'" :setting="setting" />
|
||||
<DropdownSetting v-if="setting.type === 'dropdown'" :setting="setting" />
|
||||
<RadioSetting v-if="setting.type === 'radio'" :setting="setting" />
|
||||
<SliderSetting v-if="setting.type === 'slider'" :setting="setting" />
|
||||
<ColourSetting v-if="setting.type === 'colour'" :setting="setting" />
|
||||
<KeybindSetting v-if="setting.type === 'keybind'" :setting="setting" />
|
||||
<FileSetting v-if="setting.type === 'file'" :setting="setting" />
|
||||
<GuildSetting v-if="setting.type === 'guild'" :setting="setting" />
|
||||
<ArraySetting v-if="setting.type === 'array'" :setting="setting" />
|
||||
<KeyValuePair v-if="setting.type === 'kvp'" :setting="setting"/>
|
||||
<CustomSetting v-if="setting.type === 'custom'" :setting="setting" />
|
||||
<StringSetting v-else-if="setting.type === 'text' && !setting.multiline" :setting="setting" />
|
||||
<MultilineTextSetting v-else-if="setting.type === 'text' && setting.multiline" :setting="setting" />
|
||||
<NumberSetting v-else-if="setting.type === 'number'" :setting="setting" />
|
||||
<DropdownSetting v-else-if="setting.type === 'dropdown'" :setting="setting" />
|
||||
<RadioSetting v-else-if="setting.type === 'radio'" :setting="setting" />
|
||||
<SliderSetting v-else-if="setting.type === 'slider'" :setting="setting" />
|
||||
<ColourSetting v-else-if="setting.type === 'colour'" :setting="setting" />
|
||||
<KeybindSetting v-else-if="setting.type === 'keybind'" :setting="setting" />
|
||||
<FileSetting v-else-if="setting.type === 'file'" :setting="setting" />
|
||||
<GuildSetting v-else-if="setting.type === 'guild'" :setting="setting" />
|
||||
<ArraySetting v-else-if="setting.type === 'array'" :setting="setting" />
|
||||
<Collection v-else-if="setting.type === 'collection'" :setting="setting" />
|
||||
<KeyValuePair v-else-if="setting.type === 'kvp'" :setting="setting" />
|
||||
<SecureKeyValuePair v-else-if="setting.type === 'securekvp'" :setting="setting" />
|
||||
<CustomSetting v-else-if="setting.type === 'custom'" :setting="setting" />
|
||||
<div class="bd-form-divider"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -42,7 +44,9 @@
|
|||
import FileSetting from './File.vue';
|
||||
import GuildSetting from './Guild.vue';
|
||||
import ArraySetting from './Array.vue';
|
||||
import Collection from './Collection.vue';
|
||||
import KeyValuePair from './KeyValuePair.vue';
|
||||
import SecureKeyValuePair from './SecureKeyValuePair.vue';
|
||||
import CustomSetting from './Custom.vue';
|
||||
|
||||
export default {
|
||||
|
@ -62,7 +66,9 @@
|
|||
FileSetting,
|
||||
GuildSetting,
|
||||
ArraySetting,
|
||||
Collection,
|
||||
KeyValuePair,
|
||||
SecureKeyValuePair,
|
||||
CustomSetting
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -18,3 +18,4 @@ export { default as MiInfo } from './materialicons/Info.vue';
|
|||
export { default as MiWarning } from './materialicons/Warning.vue';
|
||||
export { default as MiSuccess } from './materialicons/Success.vue';
|
||||
export { default as AccountCircle } from './materialicons/AccountCircle.vue';
|
||||
export { default as MiLock } from './materialicons/Lock.vue';
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* BetterDiscord Material Design Icon
|
||||
* 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.
|
||||
*
|
||||
* Material Design Icons
|
||||
* Copyright (c) 2014 Google
|
||||
* Apache 2.0 LICENSE
|
||||
* https://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
*/
|
||||
|
||||
<template>
|
||||
<span class="bd-material-design-icon">
|
||||
<svg :width="size || 24" :height="size || 24" viewBox="0 0 24 24">
|
||||
<path fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 11.9994,16.998C 13.1044,16.998 13.9994,16.1021 13.9994,14.998C 13.9994,13.894 13.1044,12.998 11.9994,12.998C 10.8954,12.998 9.9994,13.894 9.9994,14.998C 9.9994,16.1021 10.8954,16.998 11.9994,16.998 Z M 17.9994,7.99813C 19.1034,7.99813 19.9994,8.89413 19.9994,9.99813L 19.9994,19.9981C 19.9994,21.1021 19.1034,21.9981 17.9994,21.9981L 5.99938,21.9981C 4.89539,21.9981 3.99938,21.1021 3.99938,19.9981L 3.99938,9.99813C 3.99938,8.89413 4.89539,7.99813 5.99938,7.99813L 6.99938,7.99813L 6.99938,5.99813C 6.99938,3.23714 9.23838,0.998133 11.9994,0.998133C 14.7604,0.998133 16.9994,3.23714 16.9994,5.99813L 16.9994,7.99813L 17.9994,7.99813 Z M 12,3C 10.3431,3 9,4.34315 9,6L 9,8L 15,8L 15,6C 15,4.34315 13.6569,3 12,3 Z " />
|
||||
</svg>
|
||||
</span>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['size']
|
||||
}
|
||||
</script>
|
|
@ -9,13 +9,13 @@
|
|||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-item" :class="{active: item.active}" @click="$emit('click', item.id)">
|
||||
<div class="bd-item" :class="{active}" @click="$emit('click', item.id)">
|
||||
{{item.text}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['item']
|
||||
props: ['item', 'active']
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
<template>
|
||||
<SidebarButton v-if="item._type === 'button'" :item="item" @click="$emit('click', $event)" />
|
||||
<SidebarButton v-if="item._type === 'button'" :item="item" :active="active" @click="$emit('click', $event)" />
|
||||
<SidebarHeader v-else :item="item" />
|
||||
</template>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
import { SidebarHeader, SidebarButton } from './';
|
||||
|
||||
export default {
|
||||
props: ['item'],
|
||||
props: ['item', 'active'],
|
||||
components: {
|
||||
SidebarHeader,
|
||||
SidebarButton
|
||||
|
|
|
@ -3,4 +3,4 @@ export { default as Sidebar } from './Sidebar.vue';
|
|||
export { default as SidebarHeader } from './Header.vue';
|
||||
export { default as SidebarButton } from './Button.vue';
|
||||
export { default as SidebarItem } from './Item.vue';
|
||||
export { default as ContentColumn } from './ContentColumn.vue';
|
||||
export { default as ContentColumn } from './ContentColumn.vue';
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"aes256": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/aes256/-/aes256-1.0.4.tgz",
|
||||
"integrity": "sha512-yuaKOdoKebChkP+uRsQovWsJYm6qf58cQTvXBu6MM0BMnrXZ9SXEiXREBuU513ZRr+Uo2qX/Ci6EODLUu/qiHA==",
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
"node-sass": "^4.9.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aes256": "^1.0.4",
|
||||
"archiver": "^2.1.1",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
|
|
Loading…
Reference in New Issue