diff --git a/client/src/index.js b/client/src/index.js index 3eb55a0c..a2d778e7 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -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'); } diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index 0659d372..a4835847 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -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 = []; } - this._errors = []; return this.localContent; } catch (err) { diff --git a/client/src/modules/plugin.js b/client/src/modules/plugin.js index 4cf807d6..b07598d0 100644 --- a/client/src/modules/plugin.js +++ b/client/src/modules/plugin.js @@ -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); diff --git a/client/src/modules/pluginmanager.js b/client/src/modules/pluginmanager.js index 1b640850..1cff6af5 100644 --- a/client/src/modules/pluginmanager.js +++ b/client/src/modules/pluginmanager.js @@ -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(); diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index 8cee8f98..b8250590 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -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'; } @@ -195,11 +207,11 @@ export default class ThemeManager extends ContentManager { } if (typeof value === 'boolean' || typeof value === 'number') { - return `$${name}: ${value};`; + return `$${name}: ${value};`; } if (typeof value === 'string') { - return `$${name}: ${setting.scss_raw ? value : `'${setting.value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'')}'`};`; + return `$${name}: ${setting.scss_raw ? value : `'${setting.value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'')}'`};`; } } diff --git a/client/src/styles/partials/bdsettings/button.scss b/client/src/styles/partials/bdsettings/button.scss index 84f60112..3af9a8be 100644 --- a/client/src/styles/partials/bdsettings/button.scss +++ b/client/src/styles/partials/bdsettings/button.scss @@ -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; diff --git a/client/src/styles/partials/bdsettings/plugin-settings-modal.scss b/client/src/styles/partials/bdsettings/plugin-settings-modal.scss index aa4a5ad3..fd423cb0 100644 --- a/client/src/styles/partials/bdsettings/plugin-settings-modal.scss +++ b/client/src/styles/partials/bdsettings/plugin-settings-modal.scss @@ -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; + } + } } diff --git a/client/src/styles/partials/bdsettings/tooltips.scss b/client/src/styles/partials/bdsettings/tooltips.scss index 7b789799..0ec5e69f 100644 --- a/client/src/styles/partials/bdsettings/tooltips.scss +++ b/client/src/styles/partials/bdsettings/tooltips.scss @@ -1,9 +1,9 @@ -bdtooltips { +bd-tooltips { left: 0; position: absolute; right: 0; top: 0; - z-index: 9000; + z-index: 9001; } .bd-tooltip { diff --git a/client/src/styles/partials/generic/index.scss b/client/src/styles/partials/generic/index.scss index 8fda68bc..ba7972dc 100644 --- a/client/src/styles/partials/generic/index.scss +++ b/client/src/styles/partials/generic/index.scss @@ -4,5 +4,4 @@ @import './forms.scss'; @import './forms/index.scss'; @import './material-buttons.scss'; -@import './modals.scss'; @import './drawers.scss'; diff --git a/client/src/styles/partials/generic/modals.scss b/client/src/styles/partials/generic/modals.scss deleted file mode 100644 index 2ae89057..00000000 --- a/client/src/styles/partials/generic/modals.scss +++ /dev/null @@ -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%); - } -} diff --git a/client/src/styles/partials/index.scss b/client/src/styles/partials/index.scss index dc07738d..bbe120da 100644 --- a/client/src/styles/partials/index.scss +++ b/client/src/styles/partials/index.scss @@ -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'; diff --git a/client/src/styles/partials/modals/backdrop.scss b/client/src/styles/partials/modals/backdrop.scss new file mode 100644 index 00000000..207fa298 --- /dev/null +++ b/client/src/styles/partials/modals/backdrop.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; + } +} diff --git a/client/src/styles/partials/modals/basic-modal.scss b/client/src/styles/partials/modals/basic-modal.scss new file mode 100644 index 00000000..90ea3ca6 --- /dev/null +++ b/client/src/styles/partials/modals/basic-modal.scss @@ -0,0 +1,5 @@ +.bd-modal-basic { + .bd-modal-basic-body { + padding-bottom: 15px; + } +} diff --git a/client/src/styles/partials/modals/error-modal.scss b/client/src/styles/partials/modals/error-modal.scss new file mode 100644 index 00000000..4d3deade --- /dev/null +++ b/client/src/styles/partials/modals/error-modal.scss @@ -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; +} diff --git a/client/src/styles/partials/modals/footer-alert.scss b/client/src/styles/partials/modals/footer-alert.scss new file mode 100644 index 00000000..a6b6140f --- /dev/null +++ b/client/src/styles/partials/modals/footer-alert.scss @@ -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; + } + } + } + } +} diff --git a/client/src/styles/partials/modals/header.scss b/client/src/styles/partials/modals/header.scss new file mode 100644 index 00000000..e832f837 --- /dev/null +++ b/client/src/styles/partials/modals/header.scss @@ -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); +} diff --git a/client/src/styles/partials/modals/index.scss b/client/src/styles/partials/modals/index.scss new file mode 100644 index 00000000..e36ebd94 --- /dev/null +++ b/client/src/styles/partials/modals/index.scss @@ -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'; diff --git a/client/src/styles/partials/modals/modals.scss b/client/src/styles/partials/modals/modals.scss new file mode 100644 index 00000000..0d7b2121 --- /dev/null +++ b/client/src/styles/partials/modals/modals.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; + } + } +} diff --git a/client/src/ui/bdui.js b/client/src/ui/bdui.js index e2671991..2f1fda2d 100644 --- a/client/src/ui/bdui.js +++ b/client/src/ui/bdui.js @@ -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', diff --git a/client/src/ui/components/BdSettings.vue b/client/src/ui/components/BdSettings.vue index fd394fdf..986848b6 100644 --- a/client/src/ui/components/BdSettings.vue +++ b/client/src/ui/components/BdSettings.vue @@ -12,9 +12,6 @@