commit
91a658db44
|
@ -8,7 +8,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import { DOM, BdUI } from 'ui';
|
||||
import { DOM, BdUI, Modals } from 'ui';
|
||||
import BdCss from './styles/index.scss';
|
||||
import { Events, CssEditor, Globals, PluginManager, ThemeManager, ModuleManager, WebpackModules, Settings } from 'modules';
|
||||
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||
|
@ -22,6 +22,7 @@ class BetterDiscord {
|
|||
window.events = Events;
|
||||
window.wpm = WebpackModules;
|
||||
window.bdsettings = Settings;
|
||||
window.bdmodals = Modals;
|
||||
DOM.injectStyle(BdCss, 'bdmain');
|
||||
Events.on('global-ready', this.globalReady.bind(this));
|
||||
}
|
||||
|
@ -29,8 +30,9 @@ class BetterDiscord {
|
|||
async init() {
|
||||
await Settings.loadSettings();
|
||||
await ModuleManager.initModules();
|
||||
await PluginManager.loadAllPlugins();
|
||||
await ThemeManager.loadAllThemes();
|
||||
await PluginManager.loadAllPlugins(true);
|
||||
await ThemeManager.loadAllThemes(true);
|
||||
Modals.showContentManagerErrors();
|
||||
Events.emit('ready');
|
||||
Events.emit('discord-ready');
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { FileUtils, ClientLogger as Logger } from 'common';
|
|||
import path from 'path';
|
||||
import { Events } from 'modules';
|
||||
import { Error } from 'structs';
|
||||
import { Modals } from 'ui';
|
||||
|
||||
export default class {
|
||||
|
||||
|
@ -28,7 +29,7 @@ export default class {
|
|||
return this._contentPath ? this._contentPath : (this._contentPath = Globals.getObject('paths').find(path => path.id === this.pathId).path);
|
||||
}
|
||||
|
||||
static async loadAllContent() {
|
||||
static async loadAllContent(supressErrors) {
|
||||
try {
|
||||
await FileUtils.ensureDirectory(this.contentPath);
|
||||
const directories = await FileUtils.listDirectory(this.contentPath);
|
||||
|
@ -47,15 +48,15 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.errors.length) {
|
||||
Events.emit('bd-error', {
|
||||
header: `${this.moduleName} - one or more ${this.contentType}(s) failed to load`,
|
||||
if (this.errors.length && !supressErrors) {
|
||||
Modals.error({
|
||||
header: `${this.moduleName} - ${this.errors.length} ${this.contentType}${this.errors.length !== 1 ? 's' : ''} failed to load`,
|
||||
module: this.moduleName,
|
||||
type: 'err',
|
||||
content: this.errors
|
||||
});
|
||||
}
|
||||
this._errors = [];
|
||||
}
|
||||
|
||||
return this.localContent;
|
||||
} catch (err) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import { FileUtils } from 'common';
|
||||
import { Modals } from 'ui';
|
||||
|
||||
export default class {
|
||||
|
||||
|
@ -48,6 +49,10 @@ export default class {
|
|||
}
|
||||
}
|
||||
|
||||
showSettingsModal() {
|
||||
return Modals.pluginSettings(this);
|
||||
}
|
||||
|
||||
async saveSettings(newSettings) {
|
||||
for (let category of newSettings) {
|
||||
const oldCategory = this.pluginConfig.find(c => c.category === category.category);
|
||||
|
|
|
@ -52,15 +52,15 @@ export default class extends ContentManager {
|
|||
}
|
||||
|
||||
static get moduleName() {
|
||||
return 'PluginManager';
|
||||
return 'Plugin Manager';
|
||||
}
|
||||
|
||||
static get pathId() {
|
||||
return 'plugins';
|
||||
}
|
||||
|
||||
static async loadAllPlugins() {
|
||||
const loadAll = await this.loadAllContent();
|
||||
static async loadAllPlugins(supressErrors) {
|
||||
const loadAll = await this.loadAllContent(supressErrors);
|
||||
this.localPlugins.forEach(plugin => {
|
||||
if (plugin.type === 'module') return;
|
||||
if (plugin.enabled) plugin.start();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
import ContentManager from './contentmanager';
|
||||
import { DOM } from 'ui';
|
||||
import { DOM, Modals } from 'ui';
|
||||
import { FileUtils, ClientIPC } from 'common';
|
||||
|
||||
class Theme {
|
||||
|
@ -39,6 +39,10 @@ class Theme {
|
|||
get css() { return this.userConfig.css }
|
||||
get id() { return this.name.toLowerCase().replace(/\s+/g, '-') }
|
||||
|
||||
showSettingsModal() {
|
||||
return Modals.themeSettings(this);
|
||||
}
|
||||
|
||||
async saveSettings(newSettings) {
|
||||
for (let category of newSettings) {
|
||||
const oldCategory = this.themeConfig.find(c => c.category === category.category);
|
||||
|
@ -132,6 +136,14 @@ export default class ThemeManager extends ContentManager {
|
|||
return this.localContent;
|
||||
}
|
||||
|
||||
static get contentType() {
|
||||
return 'theme';
|
||||
}
|
||||
|
||||
static get moduleName() {
|
||||
return 'Theme Manager';
|
||||
}
|
||||
|
||||
static get pathId() {
|
||||
return 'themes';
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
background-position: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 3000;
|
||||
z-index: 3001;
|
||||
cursor: pointer;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
|
@ -44,7 +44,7 @@
|
|||
background: transparent;
|
||||
opacity: 1;
|
||||
box-shadow: none;
|
||||
z-index: 90000;
|
||||
z-index: 3001;
|
||||
|
||||
.bd-settings-button-btn {
|
||||
background-image: $logoBigBw;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
.bd-plugin-settings-body {
|
||||
padding: 0 15px;
|
||||
margin: 0 0 74px;
|
||||
|
||||
.bd-switch-wrapper {
|
||||
width: 40px;
|
||||
|
@ -22,4 +23,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bd-edited {
|
||||
.bd-scroller::-webkit-scrollbar-track {
|
||||
margin-bottom: 74px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
bdtooltips {
|
||||
bd-tooltips {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 9000;
|
||||
z-index: 9001;
|
||||
}
|
||||
|
||||
.bd-tooltip {
|
||||
|
|
|
@ -4,5 +4,4 @@
|
|||
@import './forms.scss';
|
||||
@import './forms/index.scss';
|
||||
@import './material-buttons.scss';
|
||||
@import './modals.scss';
|
||||
@import './drawers.scss';
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
.bd-backdrop {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
background: #000;
|
||||
opacity: .85;
|
||||
padding: 20px;
|
||||
z-index: 9000;
|
||||
justify-content: center;
|
||||
|
||||
animation: bd-backdrop-in 0.22s ease;
|
||||
&.bd-backdrop-out {
|
||||
animation: bd-backdrop-out 0.22s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal {
|
||||
position: fixed;
|
||||
align-content: space-around;
|
||||
display: flex;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
padding: 60px;
|
||||
transform: scale(1) translateZ(0px);
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
z-index: 9001;
|
||||
justify-content: center;
|
||||
animation: bd-modal-in 0.22s ease;
|
||||
|
||||
&.bd-modal-out {
|
||||
animation: bd-modal-out 0.22s ease;
|
||||
}
|
||||
|
||||
.bd-modal-header .bd-modal-icon .bd-material-design-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.bd-err {
|
||||
.bd-modal-header .bd-modal-icon svg {
|
||||
fill: $colerr;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-body .bd-scroller-wrap .bd-scroller {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.bd-modal-controls {
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
border-top: 1px solid #4a4a4a;
|
||||
|
||||
.bd-modal-tip {
|
||||
flex-grow: 1;
|
||||
line-height: 26px;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.bd-button {
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal .bd-modal-inner {
|
||||
background: #36393e;
|
||||
contain: layout;
|
||||
flex-direction: column;
|
||||
pointer-events: auto;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border-radius: 4px;
|
||||
max-height: 100%;
|
||||
max-width: 500px;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.bd-modal .bd-modal-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bd-modal {
|
||||
.bd-modal-header {
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
flex: 0 0;
|
||||
-webkit-transition: -webkit-box-shadow .1s ease-out;
|
||||
transition: -webkit-box-shadow .1s ease-out;
|
||||
transition: box-shadow .1s ease-out;
|
||||
|
||||
.bd-modal-headertext {
|
||||
color: #FFF;
|
||||
font-weight: 700;
|
||||
flex-grow: 1;
|
||||
line-height: 18px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.bd-modal-x {
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: -2px -2px -2px 10px;
|
||||
padding: 2px;
|
||||
|
||||
.bd-material-design-icon {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #2d2f34;
|
||||
|
||||
.bd-material-design-icon {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bd-modal-scrolled .bd-modal-header {
|
||||
-webkit-box-shadow: 0 1px 0 0 rgba(24,25,28,.3), 0 1px 2px 0 rgba(24,25,28,.3);
|
||||
box-shadow: 0 1px 0 0 rgba(24,25,28,.3), 0 1px 2px 0 rgba(24,25,28,.3);
|
||||
}
|
||||
|
||||
.bd-modal-body {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.bd-modal-footer {
|
||||
.bd-footer-alert {
|
||||
margin: 10px;
|
||||
height: 0;
|
||||
display: flex;
|
||||
background-color: rgba(32, 34, 37, 0.9);
|
||||
box-shadow: 0 2px 10px 0 rgba(0,0,0,.2);
|
||||
padding: 10px 10px 10px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
transition: all .2s ease-in-out;
|
||||
|
||||
&.bd-warn {
|
||||
background-color: $colerr;
|
||||
animation: bd-warn-shake 0.4s;
|
||||
}
|
||||
|
||||
&.bd-active {
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.bd-footer-alert-text {
|
||||
flex: 1 1 auto;
|
||||
color: #FFF;
|
||||
font-weight: 700;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
.bd-button {
|
||||
height: 30px;
|
||||
border-radius: 3px;
|
||||
padding: 2px 16px;
|
||||
|
||||
&.bd-tp {
|
||||
background: transparent;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-modal-error-title {
|
||||
padding: 5px;
|
||||
background: rgba(0,0,0,.3);
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.bd-modal-error {
|
||||
margin-top: 5px;
|
||||
|
||||
.bd-scroller-wrap {
|
||||
background: rgba(0,0,0,.2);
|
||||
|
||||
.bd-scroller {
|
||||
overflow-x: auto;
|
||||
padding: 0;
|
||||
|
||||
&::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-scroller-wrap {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bd-modal-error.bd-open {
|
||||
.bd-modal-error-body {
|
||||
transform: scaleY(1) translateY(0%);
|
||||
margin-top: 0%;
|
||||
opacity: 1;
|
||||
user-select: all;
|
||||
span {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
.bd-scroller-wrap {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-modal-error-body {
|
||||
white-space: pre-wrap;
|
||||
font-size: 12px;
|
||||
font-family: 'Consolas';
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
max-height: 100px;
|
||||
width: auto;
|
||||
transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease;
|
||||
transform: scaleY(0) translateY(0%);
|
||||
margin-top: -50%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bd-modal-titlelink {
|
||||
cursor: pointer;
|
||||
color: $colbdblue;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: lighten($colbdblue, 5%);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
@import './sidebarview/index.scss';
|
||||
@import './bdsettings/index.scss';
|
||||
@import './generic/index.scss';
|
||||
@import './modals/index.scss';
|
||||
@import './profilebadges.scss';
|
||||
|
||||
@import './discordoverrides.scss';
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
.bd-backdrop {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
background: #000;
|
||||
opacity: .85;
|
||||
padding: 20px;
|
||||
z-index: 9000;
|
||||
justify-content: center;
|
||||
|
||||
animation: bd-backdrop-in 0.22s ease;
|
||||
&.bd-backdrop-out {
|
||||
animation: bd-backdrop-out 0.22s ease;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
.bd-modal-basic {
|
||||
.bd-modal-basic-body {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
.bd-modal.bd-err {
|
||||
.bd-modal-header .bd-modal-icon svg {
|
||||
fill: $colerr;
|
||||
}
|
||||
|
||||
.bd-modal-body {
|
||||
padding-bottom: 15px;
|
||||
min-height: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-modal-error-title {
|
||||
padding: 5px;
|
||||
background: rgba(0,0,0,.3);
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.bd-modal-error {
|
||||
margin-top: 5px;
|
||||
|
||||
.bd-scroller-wrap {
|
||||
background: rgba(0,0,0,.2);
|
||||
|
||||
.bd-scroller {
|
||||
overflow-x: auto;
|
||||
padding: 0;
|
||||
|
||||
&::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-scroller-wrap {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.bd-modal-error.bd-open {
|
||||
.bd-modal-error-body {
|
||||
transform: scaleY(1) translateY(0%);
|
||||
margin-top: 0%;
|
||||
opacity: 1;
|
||||
user-select: all;
|
||||
span {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
.bd-scroller-wrap {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-error .bd-modal-error-body {
|
||||
white-space: pre-wrap;
|
||||
font-size: 12px;
|
||||
font-family: 'Consolas';
|
||||
padding: 0 5px;
|
||||
border-radius: 3px;
|
||||
max-height: 100px;
|
||||
width: auto;
|
||||
transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease;
|
||||
transform: scaleY(0) translateY(0%);
|
||||
margin-top: -50%;
|
||||
opacity: 0;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
.bd-modal-footer {
|
||||
.bd-footer-alert {
|
||||
margin: -64px 10px 10px;
|
||||
height: 0;
|
||||
display: flex;
|
||||
background-color: rgba(32, 34, 37, 0.9);
|
||||
box-shadow: 0 2px 10px 0 rgba(0,0,0,.2);
|
||||
padding: 10px 10px 10px 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
transform: translateY(100%);
|
||||
opacity: 0;
|
||||
transition: all .2s ease-in-out;
|
||||
position: relative;
|
||||
|
||||
&.bd-warn {
|
||||
background-color: $colerr;
|
||||
animation: bd-warn-shake 0.4s;
|
||||
}
|
||||
|
||||
&.bd-active {
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.bd-footer-alert-text {
|
||||
flex: 1 1 auto;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
.bd-button {
|
||||
height: 30px;
|
||||
border-radius: 3px;
|
||||
padding: 2px 16px;
|
||||
|
||||
&.bd-tp {
|
||||
background: transparent;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
.bd-modal-header {
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
flex: 0 0;
|
||||
-webkit-transition: -webkit-box-shadow .1s ease-out;
|
||||
transition: -webkit-box-shadow .1s ease-out;
|
||||
transition: box-shadow .1s ease-out;
|
||||
|
||||
.bd-modal-headertext {
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
flex-grow: 1;
|
||||
line-height: 18px;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.bd-modal-icon .bd-material-design-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.bd-modal-x {
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: -2px -2px -2px 10px;
|
||||
padding: 2px;
|
||||
|
||||
.bd-material-design-icon {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #2d2f34;
|
||||
|
||||
.bd-material-design-icon {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-scrolled .bd-modal-header {
|
||||
-webkit-box-shadow: 0 1px 0 0 rgba(24,25,28,.3), 0 1px 2px 0 rgba(24,25,28,.3);
|
||||
box-shadow: 0 1px 0 0 rgba(24,25,28,.3), 0 1px 2px 0 rgba(24,25,28,.3);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
@import './backdrop.scss';
|
||||
@import './modals.scss';
|
||||
@import './header.scss';
|
||||
@import './footer-alert.scss';
|
||||
|
||||
@import './basic-modal.scss';
|
||||
@import './error-modal.scss';
|
|
@ -0,0 +1,96 @@
|
|||
.bd-modal-wrap {
|
||||
transition: all 0.2s ease;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 9000;
|
||||
|
||||
.bd-modal-close-area {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal {
|
||||
position: fixed;
|
||||
align-content: space-around;
|
||||
display: flex;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
padding: 60px;
|
||||
transform: scale(1) translateZ(0px);
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
z-index: 9001;
|
||||
justify-content: center;
|
||||
animation: bd-modal-in 0.22s ease;
|
||||
|
||||
&.bd-modal-out {
|
||||
animation: bd-modal-out 0.22s ease;
|
||||
}
|
||||
|
||||
.bd-modal-inner {
|
||||
background: #36393e;
|
||||
contain: layout;
|
||||
flex-direction: column;
|
||||
pointer-events: auto;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
border-radius: 4px;
|
||||
max-height: 100%;
|
||||
max-width: 500px;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.bd-modal-body {
|
||||
padding: 0 15px;
|
||||
display: flex;
|
||||
|
||||
.bd-scroller-wrap .bd-scroller {
|
||||
color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-titlelink {
|
||||
cursor: pointer;
|
||||
color: $colbdblue;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: lighten($colbdblue, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
.bd-modal-controls {
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
border-top: 1px solid #4a4a4a;
|
||||
|
||||
.bd-modal-tip {
|
||||
flex-grow: 1;
|
||||
line-height: 26px;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.bd-button {
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,9 +35,9 @@ export default class {
|
|||
}
|
||||
|
||||
static injectUi() {
|
||||
DOM.createElement('bdtooltips').appendTo(DOM.bdBody);
|
||||
DOM.createElement('div', null, 'bd-settings').appendTo(DOM.bdBody);
|
||||
DOM.createElement('div', null, 'bd-modals').appendTo(DOM.bdModals);
|
||||
DOM.createElement('bd-tooltips').appendTo(DOM.bdBody);
|
||||
|
||||
const modals = new Vue({
|
||||
el: '#bd-modals',
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
<div class="bd-settings" :class="{active: active}" @keyup="close">
|
||||
<SidebarView :contentVisible="this.activeIndex >= 0" :animating="this.animating" :class="{'bd-stop': !first}">
|
||||
<Sidebar slot="sidebar">
|
||||
<div class="bd-settings-button bd-active">
|
||||
<div class="bd-settings-button-btn"></div>
|
||||
</div>
|
||||
<div class="bd-settings-x" @click="close">
|
||||
<MiClose size="17"/>
|
||||
<span class="bd-x-text">ESC</span>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<template>
|
||||
<div class="bd-settings-wrapper" :class="[{active: active}, 'platform-' + this.platform]">
|
||||
<div class="bd-settings-button" @click="showSettings">
|
||||
<div class="bd-settings-button" :class="{'bd-active': active}" @click="showSettings">
|
||||
<div class="bd-settings-button-btn" :class="[{'bd-loading': !loaded}]"></div>
|
||||
</div>
|
||||
<BdSettings :active="active" :close="hideSettings" />
|
||||
|
|
|
@ -8,66 +8,50 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
<template>
|
||||
<div class="bd-modals-container">
|
||||
<div v-for="(modal, index) in modals" :key="`bd-modal-${index}`">
|
||||
<div v-if="index === 0" class="bd-backdrop" @click="closeModal(index)"></div>
|
||||
<div v-else :style="{opacity: 0}" class="bd-backdrop" @click="closeModal(index)"></div>
|
||||
<Modal :headerText="modal.header"
|
||||
:close="() => closeModal(index)"
|
||||
:class="[{'bd-err': modal.type && modal.type === 'err'}, {'bd-modal-out': modal.closing}]">
|
||||
<MiError v-if="modal.type === 'err'" slot="icon" size="20"/>
|
||||
<div slot="body">
|
||||
<div v-for="(content, index) in modal.content">
|
||||
<ErrorModal v-if="content._type === 'err'" :content="content" :hideStack="hideStack" :showStack="showStack"/>
|
||||
<div v-for="(modal, index) in modals.stack" :key="`bd-modal-${index}`">
|
||||
<div class="bd-backdrop" :class="{'bd-backdrop-out': modal.closing}" :style="{opacity: index === 0 ? undefined : 0}"></div>
|
||||
<div class="bd-modal-wrap" :style="{transform: `scale(${downscale(index + 1, 0.2)})`, opacity: downscale(index + 1, 1)}">
|
||||
<div class="bd-modal-close-area" @click="closeModal(modal)"></div>
|
||||
<component :is="modal.component" />
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="bd-modal-controls">
|
||||
<span class="bd-modal-tip">Ctrl+Shift+I for more details</span>
|
||||
<div class="bd-button bd-ok" @click="closeModal(index)">
|
||||
OK
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { Events } from 'modules';
|
||||
import { Modals } from 'ui';
|
||||
import { Modal } from '../common';
|
||||
import { MiError } from '../common/MaterialIcon';
|
||||
import ErrorModal from '../common/ErrorModal.vue';
|
||||
import ErrorModal from './modals/ErrorModal.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal, MiError
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modals: []
|
||||
}
|
||||
modals: Modals,
|
||||
eventListener: null
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Modal, MiError, ErrorModal
|
||||
},
|
||||
beforeMount() {
|
||||
Events.on('bd-error', e => {
|
||||
e.closing = false;
|
||||
this.modals.push(e);
|
||||
console.log(this.modals);
|
||||
created() {
|
||||
console.log(this);
|
||||
Events.on('bd-refresh-modals', this.eventListener = () => {
|
||||
this.$forceUpdate();
|
||||
});
|
||||
},
|
||||
destroyed() {
|
||||
if (this.eventListener) Events.off('bd-refresh-modals', this.eventListener);
|
||||
},
|
||||
methods: {
|
||||
closeModal(index) {
|
||||
this.modals[index].closing = true;
|
||||
setTimeout(() => {
|
||||
this.modals.splice(index, 1);
|
||||
}, 200);
|
||||
closeModal(modal) {
|
||||
modal.close();
|
||||
},
|
||||
showStack(error) {
|
||||
error.showStack = true;
|
||||
},
|
||||
hideStack(error) {
|
||||
error.showStack = false;
|
||||
downscale(index, times) {
|
||||
return 1 - ((this.modals.stack.filter(m => !m.closing).length - index) * times);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,28 +32,26 @@
|
|||
<div class="bd-spinner-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<PluginSettingsModal v-if="settingsOpen !== null" :plugin="settingsOpen" :close="closeSettings" />
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { PluginManager } from 'modules';
|
||||
import { Modals } from 'ui';
|
||||
import { SettingsWrapper } from './';
|
||||
import PluginCard from './PluginCard.vue';
|
||||
import PluginSettingsModal from './PluginSettingsModal.vue';
|
||||
import { MiRefresh } from '../common';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
local: true,
|
||||
settingsOpen: null,
|
||||
localPlugins: PluginManager.localPlugins
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SettingsWrapper, PluginCard, PluginSettingsModal,
|
||||
SettingsWrapper, PluginCard,
|
||||
MiRefresh
|
||||
},
|
||||
methods: {
|
||||
|
@ -91,12 +89,8 @@
|
|||
})();
|
||||
},
|
||||
showSettings(plugin) {
|
||||
this.settingsOpen = plugin;
|
||||
},
|
||||
closeSettings() {
|
||||
this.settingsOpen = null;
|
||||
return Modals.pluginSettings(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -32,29 +32,26 @@
|
|||
<div class="bd-spinner-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<ThemeSettingsModal v-if="settingsOpen !== null" :theme="settingsOpen" :close="closeSettings" />
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { ThemeManager } from 'modules';
|
||||
import { Modals } from 'ui';
|
||||
import { SettingsWrapper } from './';
|
||||
import { MiRefresh } from '../common';
|
||||
import ThemeSettingsModal from './ThemeSettingsModal.vue';
|
||||
import ThemeCard from './ThemeCard.vue';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
local: true,
|
||||
settingsOpen: null,
|
||||
localThemes: ThemeManager.localThemes
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SettingsWrapper, ThemeCard,
|
||||
ThemeSettingsModal,
|
||||
MiRefresh
|
||||
},
|
||||
methods: {
|
||||
|
@ -92,12 +89,8 @@
|
|||
})();
|
||||
},
|
||||
showSettings(theme) {
|
||||
this.settingsOpen = theme;
|
||||
},
|
||||
closeSettings() {
|
||||
this.settingsOpen = null;
|
||||
return Modals.themeSettings(theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* BetterDiscord Basic 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>
|
||||
<Modal :class="['bd-modal-basic', {'bd-modal-out': modal.closing}]" :headerText="modal.title" :close="modal.close">
|
||||
<div slot="body" class="bd-modal-basic-body">{{ modal.text }}</div>
|
||||
<div slot="footer" class="bd-modal-controls">
|
||||
<div class="bd-flex-grow"></div>
|
||||
<div class="bd-button bd-ok" @click="modal.close">OK</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { Modal } from '../../common';
|
||||
|
||||
export default {
|
||||
props: ['modal'],
|
||||
components: {
|
||||
Modal
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<Modal :headerText="modal.event.header" :close="modal.close"
|
||||
:class="[{'bd-err': modal.event.type && modal.event.type === 'err'}, {'bd-modal-out': modal.closing}]">
|
||||
<MiError v-if="modal.event.type === 'err'" slot="icon" size="20"/>
|
||||
<div slot="body">
|
||||
<div v-for="(content, index) in modal.event.content">
|
||||
<div v-if="content._type === 'err'" class="bd-modal-error" :class="{'bd-open': content.showStack}">
|
||||
<div class="bd-modal-error-title bd-flex">
|
||||
<span class="bd-modal-title-text bd-flex-grow">{{content.message}}</span>
|
||||
<span class="bd-modal-titlelink" v-if="content.showStack" @click="() => { content.showStack = false; $forceUpdate(); }">Hide Stacktrace</span>
|
||||
<span class="bd-modal-titlelink" v-else @click="() => { content.showStack = true; $forceUpdate(); }">Show Stacktrace</span>
|
||||
</div>
|
||||
<div class="bd-scroller-wrap">
|
||||
<div class="bd-scroller">
|
||||
<div class="bd-modal-error-body"><span>{{content.err.message}}</span>
|
||||
{{content.stackTrace}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="bd-modal-controls">
|
||||
<span class="bd-modal-tip">Press {{ platformInspectorKey }} for more details</span>
|
||||
<div class="bd-button bd-ok" @click="modal.close">OK</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { Modal } from '../../common';
|
||||
import { MiError } from '../../common/MaterialIcon';
|
||||
|
||||
const process = window.require('process');
|
||||
|
||||
export default {
|
||||
props: ['modal'],
|
||||
components: {
|
||||
Modal, MiError
|
||||
},
|
||||
computed: {
|
||||
platformInspectorKey() {
|
||||
return process.platform === 'darwin' ? 'Cmd+Option+I' : 'Ctrl+Shift+I';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
<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="plugin.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': closing}">
|
||||
<Modal :headerText="plugin.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': modal.closing}">
|
||||
<SettingsPanel :settings="configCache" :change="settingChange" slot="body" class="bd-plugin-settings-body" />
|
||||
<div slot="footer" class="bd-footer-alert" :class ="{'bd-active': changed, 'bd-warn': warnclose}">
|
||||
<div class="bd-footer-alert-text">Unsaved changes</div>
|
||||
|
@ -27,11 +26,11 @@
|
|||
<script>
|
||||
// Imports
|
||||
import Vue from 'vue';
|
||||
import { Modal } from '../common';
|
||||
import SettingsPanel from './SettingsPanel.vue';
|
||||
import { Modal } from '../../common';
|
||||
import SettingsPanel from '../SettingsPanel.vue';
|
||||
|
||||
export default {
|
||||
props: ['plugin','close'],
|
||||
props: ['modal'],
|
||||
data() {
|
||||
return {
|
||||
changed: false,
|
||||
|
@ -43,7 +42,10 @@
|
|||
},
|
||||
components: {
|
||||
Modal,
|
||||
SettingsPanel,
|
||||
SettingsPanel
|
||||
},
|
||||
computed: {
|
||||
plugin() { return this.modal.plugin; }
|
||||
},
|
||||
methods: {
|
||||
checkForChanges() {
|
||||
|
@ -96,7 +98,7 @@
|
|||
if (!this.changed) {
|
||||
this.closing = true;
|
||||
setTimeout(() => {
|
||||
this.close();
|
||||
this.modal.close();
|
||||
}, 200);
|
||||
return;
|
||||
}
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
<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}">
|
||||
<Modal :headerText="theme.name + ' Settings'" :close="attemptToClose" :class="{'bd-modal-out': modal.closing}">
|
||||
<SettingsPanel :settings="configCache" :change="settingChange" slot="body" class="bd-plugin-settings-body" />
|
||||
<div slot="footer" class="bd-footer-alert" :class ="{'bd-active': changed, 'bd-warn': warnclose}">
|
||||
<div class="bd-footer-alert-text">Unsaved changes</div>
|
||||
|
@ -27,11 +26,11 @@
|
|||
<script>
|
||||
// Imports
|
||||
import Vue from 'vue';
|
||||
import { Modal } from '../common';
|
||||
import SettingsPanel from './SettingsPanel.vue';
|
||||
import { Modal } from '../../common';
|
||||
import SettingsPanel from '../SettingsPanel.vue';
|
||||
|
||||
export default {
|
||||
props: ['theme', 'close'],
|
||||
props: ['modal'],
|
||||
data() {
|
||||
return {
|
||||
changed: false,
|
||||
|
@ -45,6 +44,9 @@
|
|||
Modal,
|
||||
SettingsPanel
|
||||
},
|
||||
computed: {
|
||||
theme() { return this.modal.theme; }
|
||||
},
|
||||
methods: {
|
||||
checkForChanges() {
|
||||
let changed = false;
|
||||
|
@ -96,7 +98,7 @@
|
|||
if (!this.changed) {
|
||||
this.closing = true;
|
||||
setTimeout(() => {
|
||||
this.close();
|
||||
this.modal.close();
|
||||
}, 200);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* BetterDiscord Modals
|
||||
* 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 { FileUtils } from 'common';
|
||||
import { Events, PluginManager, ThemeManager } from 'modules';
|
||||
import BasicModal from './components/bd/modals/BasicModal.vue';
|
||||
import ErrorModal from './components/bd/modals/ErrorModal.vue';
|
||||
import PluginSettingsModal from './components/bd/modals/PluginSettingsModal.vue';
|
||||
import ThemeSettingsModal from './components/bd/modals/ThemeSettingsModal.vue';
|
||||
|
||||
export default class {
|
||||
|
||||
static add(modal, component) {
|
||||
modal.component = modal.component || {
|
||||
template: '<custom-modal :modal="modal" />',
|
||||
components: { 'custom-modal': component },
|
||||
data() { return { modal }; },
|
||||
created() { modal.vue = this; }
|
||||
};
|
||||
modal.closing = false;
|
||||
modal.close = () => this.close(modal);
|
||||
|
||||
this.stack.push(modal);
|
||||
Events.emit('bd-refresh-modals');
|
||||
return modal;
|
||||
}
|
||||
|
||||
static close(modal) {
|
||||
return new Promise((resolve, reject) => {
|
||||
modal.closing = true;
|
||||
setTimeout(() => {
|
||||
this._stack = this.stack.filter(m => m !== modal);
|
||||
Events.emit('bd-refresh-modals');
|
||||
resolve();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
static closeAll() {
|
||||
for (let modal of this.stack)
|
||||
modal.close();
|
||||
}
|
||||
|
||||
static closeLast() {
|
||||
if (!this.stack.length) return;
|
||||
this.stack[this.stack.length - 1].close();
|
||||
}
|
||||
|
||||
static basic(title, text) {
|
||||
return this.add({ title, text }, BasicModal);
|
||||
}
|
||||
|
||||
static error(event) {
|
||||
return this.add({ event }, ErrorModal);
|
||||
}
|
||||
|
||||
static showContentManagerErrors() {
|
||||
// Get any errors from PluginManager and ThemeManager
|
||||
this.error({
|
||||
header:
|
||||
(PluginManager.errors.length && ThemeManager.errors.length ? '' :
|
||||
(PluginManager.errors.length ? PluginManager.moduleName : ThemeManager.moduleName) + ' - ') +
|
||||
(PluginManager.errors.length ? `${PluginManager.errors.length} ${PluginManager.contentType}${PluginManager.errors.length !== 1 ? 's' : ''}` : '') +
|
||||
(PluginManager.errors.length && ThemeManager.errors.length ? ' and ' : '') +
|
||||
(ThemeManager.errors.length ? `${ThemeManager.errors.length} ${ThemeManager.contentType}${ThemeManager.errors.length !== 1 ? 's' : ''}` : '') +
|
||||
' failed to load',
|
||||
module: (PluginManager.errors.length && ThemeManager.errors.length ? 'Content Manager' :
|
||||
(PluginManager.errors.length ? PluginManager.moduleName : ThemeManager.moduleName)),
|
||||
type: 'err',
|
||||
content: ([]).concat(PluginManager.errors).concat(ThemeManager.errors)
|
||||
});
|
||||
}
|
||||
|
||||
static pluginSettings(plugin) {
|
||||
return this.add({ plugin }, PluginSettingsModal);
|
||||
}
|
||||
|
||||
static themeSettings(theme) {
|
||||
return this.add({ theme }, ThemeSettingsModal);
|
||||
}
|
||||
|
||||
static get stack() {
|
||||
return this._stack ? this._stack : (this._stack = []);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
export { default as DOM } from './dom';
|
||||
export { default as BdUI } from './bdui';
|
||||
export { default as VueInjector } from './vueinjector';
|
||||
export { default as Modals } from './modals';
|
||||
export { default as ProfileBadges } from './profilebadges';
|
||||
|
|
|
@ -13,7 +13,7 @@ import Vue from 'vue';
|
|||
import VTooltip from 'v-tooltip';
|
||||
|
||||
Vue.use(VTooltip, {
|
||||
defaultContainer: 'bdtooltips',
|
||||
defaultContainer: 'bd-tooltips',
|
||||
defaultClass: 'bd-tooltip',
|
||||
defaultTargetClass: 'bd-has-tooltip',
|
||||
defaultInnerSelector: '.bd-tooltip-inner',
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = (Plugin, Api, Vendor) => {
|
|||
onStop() {
|
||||
Events.unsubscribeAll();
|
||||
Logger.log('onStop');
|
||||
console.log(this.showSettingsModal());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue