diff --git a/client/src/modules/csseditor.js b/client/src/modules/csseditor.js index b77c08f3..bd840ac9 100644 --- a/client/src/modules/csseditor.js +++ b/client/src/modules/csseditor.js @@ -13,14 +13,53 @@ import { DOM } from 'ui'; export default class { - static async show() { - const t = await ClientIPC.send('openCssEditor', {}); - ClientIPC.send('setCss', { css: DOM.getStyleCss('bd-customcss') }); + static init() { + ClientIPC.on('bd-get-scss', () => this.sendToEditor('set-scss', { scss: this.scss })); + ClientIPC.on('bd-update-scss', (e, scss) => this.updateScss(scss)); - ClientIPC.on('bd-update-css', this.updateCss); + ClientIPC.on('bd-save-scss', async (e, scss) => { + this.updateScss(scss); + e.reply(await this.save(scss)); + }); } - static updateCss(e, css) { + static async show() { + await ClientIPC.send('openCssEditor', {}); + } + + static updateScss(scss) { + this.compile(scss).then(css => { + this.css = css; + this._scss = scss; + this.sendToEditor('scss-error', null); + }).catch(err => { + this.sendToEditor('scss-error', err); + }); + } + + static async save(scss) { + console.log('Saving SCSS:', scss); + } + + static async compile(scss) { + return await ClientIPC.send('bd-compileSass', { data: scss }); + } + + static async sendToEditor(channel, data) { + return await ClientIPC.send('sendToCssEditor', { channel, data }); + } + + static get scss() { + return this._scss || ''; + } + + static set scss(scss) { + this.sendToEditor('set-scss', { scss: this.scss }); + this.updateScss(scss); + } + + static set css(css) { DOM.injectStyle(css, 'bd-customcss'); } + } diff --git a/client/src/modules/modulemanager.js b/client/src/modules/modulemanager.js index da62132a..cdf51dce 100644 --- a/client/src/modules/modulemanager.js +++ b/client/src/modules/modulemanager.js @@ -10,7 +10,7 @@ /*Module Manager initializes all modules when everything is ready*/ -import { Events, SocketProxy, EventHook } from 'modules'; +import { Events, SocketProxy, EventHook, CssEditor } from 'modules'; import { ProfileBadges } from 'ui'; export default class { @@ -19,7 +19,8 @@ export default class { return this._modules ? this._modules : (this._modules = [ new ProfileBadges(), new SocketProxy(), - new EventHook() + new EventHook(), + CssEditor ]); } diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index 8cee8f98..ed6805a9 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -101,7 +101,7 @@ class Theme { let css = ''; if (this.info.type === 'sass') { css = await ClientIPC.send('bd-compileSass', { - scss: ThemeManager.getConfigAsSCSS(this.themeConfig), + data: ThemeManager.getConfigAsSCSS(this.themeConfig), path: this.paths.mainPath.replace(/\\/g, '/') }); console.log(css); @@ -195,11 +195,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/core/src/main.js b/core/src/main.js index 10a77bc1..62abe1f3 100644 --- a/core/src/main.js +++ b/core/src/main.js @@ -55,7 +55,7 @@ class Comms { }); BDIpc.on('bd-openCssEditor', o => CSSEditor.openEditor(o)); - BDIpc.on('bd-setCss', o => CSSEditor.setCSS(o.args)); + BDIpc.on('bd-sendToCssEditor', o => CSSEditor.send(o.args.channel, o.args.data)); BDIpc.on('bd-readFile', this.readFile); BDIpc.on('bd-readJson', o => this.readFile(o, true)); @@ -67,11 +67,13 @@ class Comms { }); BDIpc.on('bd-compileSass', o => { - const { scss, path } = o.args; - if (!scss && !path) return; - const data = scss ? `${scss} @import '${path}';` : `@import '${path}';`; + if (!o.args.data && !o.args.path) return; + if (o.args.path && o.args.data) { + o.args.data = `${o.args.data} @import '${o.args.path}';`; + o.args.path = undefined; + } - sass.render({ data }, (err, result) => { + sass.render(o.args, (err, result) => { if (err) { o.reply({ err }); return; @@ -180,4 +182,4 @@ class BetterDiscord { module.exports = { BetterDiscord -} \ No newline at end of file +}; diff --git a/core/src/modules/csseditor.js b/core/src/modules/csseditor.js index 6f90f05f..11a1a7ae 100644 --- a/core/src/modules/csseditor.js +++ b/core/src/modules/csseditor.js @@ -12,6 +12,7 @@ const path = require('path'); const { BrowserWindow } = require('electron'); const { Module } = require('./modulebase'); +const { WindowUtils } = require('./utils'); class CSSEditor extends Module { @@ -26,25 +27,30 @@ class CSSEditor extends Module { } this.editor = new BrowserWindow(this.options); - this.editor.loadURL(`file://${this.editorPath}/index.html`); - this.editor.open = true; + this.editor.loadURL('about:blank'); this.editor.setSheetOffset(33); + this.editorUtils = new WindowUtils({ window: this.editor }); this.editor.webContents.on('close', () => { this.editor = null; }); this.editor.once('ready-to-show', () => { - this.editor.show() + this.editor.show(); }); this.editor.webContents.on('did-finish-load', () => { + this.editorUtils.injectScript(path.join(this.editorPath, 'csseditor.js')); o.reply(true); }); } - setCSS(css) { - this.editor.webContents.send("set-css", css); + setSCSS(scss) { + this.send('set-scss', scss); + } + + send(channel, data) { + this.editor.webContents.send(channel, data); } set alwaysOnTop(state) { @@ -69,4 +75,6 @@ class CSSEditor extends Module { } -module.exports = { 'CSSEditor': new CSSEditor() }; +module.exports = { + CSSEditor: new CSSEditor() +}; diff --git a/core/src/modules/utils.js b/core/src/modules/utils.js index b9b748bb..68f6aa82 100644 --- a/core/src/modules/utils.js +++ b/core/src/modules/utils.js @@ -133,8 +133,12 @@ class WindowUtils extends Module { injectScript(fpath, variable) { console.log(`Injecting: ${fpath}`); - if (variable) this.executeJavascript(`${variable} = require("${fpath}");`); - else this.executeJavascript(`require("${fpath}");`); + + const escaped_path = fpath.replace(/\\/g, '\\\\').replace(/"/g, '\\\"'); + const escaped_variable = variable ? variable.replace(/\\/g, '\\\\').replace(/"/g, '\\\"') : null; + + if (variable) this.executeJavascript(`window["${escaped_variable}"] = require("${escaped_path}");`); + else this.executeJavascript(`require("${escaped_path}");`); } events(event, callback) { @@ -152,4 +156,4 @@ module.exports = { Utils, FileUtils, WindowUtils -} \ No newline at end of file +}; diff --git a/csseditor/src/BDIpc.js b/csseditor/src/BDIpc.js index 36d9a7e5..711a669b 100644 --- a/csseditor/src/BDIpc.js +++ b/csseditor/src/BDIpc.js @@ -1,6 +1,6 @@ const { ipcRenderer } = window.require('electron'); -class BDIpc { +export default class { static on(channel, cb) { ipcRenderer.on(channel, (event, args) => cb(event, args)); @@ -21,6 +21,8 @@ class BDIpc { }); } -} + static sendToDiscord(channel, message) { + this.send('bd-sendToDiscord', { channel, message }); + } -module.exports = { BDIpc }; \ No newline at end of file +} diff --git a/csseditor/src/Editor.vue b/csseditor/src/Editor.vue index 4d1d7e1c..d17f18b8 100644 --- a/csseditor/src/Editor.vue +++ b/csseditor/src/Editor.vue @@ -8,7 +8,7 @@
CSS Editor
- +
@@ -16,19 +16,16 @@
Loading Please Wait...
- +
+
{{ error.formatted }}
- Live Update + Live Update
@@ -45,11 +42,9 @@ import '../../node_modules/codemirror/addon/dialog/dialog.js'; import '../../node_modules/codemirror/addon/hint/show-hint.js'; + import BDIpc from './BDIpc'; + const { remote } = window.require('electron'); - const { BDIpc } = require('./BDIpc'); - function sendToDiscord(channel, message) { - BDIpc.send('bd-sendToDiscord', { channel, message }); - } const ExcludedIntelliSenseTriggerKeys = { '8': 'backspace', @@ -103,49 +98,7 @@ '222': 'quote' }; - /*Methods*/ - function save() { - const css = this.codemirror.getValue(); - sendToDiscord('save-css', css); - } - - function update() { - const css = this.codemirror.getValue(); - sendToDiscord('update-css', css); - } - - function toggleaot() { - this.alwaysOnTop = !this.alwaysOnTop; - remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop); - } - - function close() { - window.close(); - } - - function setCss(css) { - this.loading = false; - this.codemirror.setValue(css || ''); - } - - function cmOnChange(value) { - if(this.liveUpdate) sendToDiscord('update-css', value); - } - - function cmOnKeyUp(editor, event) { - if (event.ctrlKey) return; - if (ExcludedIntelliSenseTriggerKeys[event.keyCode]) return; - cmCommands.autocomplete(editor, null, { completeSingle: false }); - } - - function toggleLiveUpdate(e) { - this.liveUpdate = !this.liveUpdate; - } - - const methods = { save, update, toggleaot, close, setCss, cmOnChange, cmOnKeyUp, toggleLiveUpdate }; - export default { - methods, data() { return { loading: true, @@ -155,7 +108,7 @@ cmOptions: { indentUnit: 4, tabSize: 4, - mode: 'css', + mode: 'text/x-scss', lineNumbers: true, theme: 'material', scrollbarStyle: 'overlay', @@ -165,7 +118,8 @@ dialog: { 'position': 'bottom' } - } + }, + error: null } }, computed: { @@ -176,18 +130,57 @@ return this.$refs.mycm; } }, - mounted: function () { + mounted() { this.codemirror.on('keyup', this.cmOnKeyUp); - BDIpc.on('set-css', (_, data) => { + BDIpc.on('set-scss', (_, data) => { if (data.error) { console.log(data.error); return; } console.log(data); - this.setCss(data.css); + this.setScss(data.scss); }); - BDIpc.send('get-css'); + BDIpc.sendToDiscord('get-scss'); + + BDIpc.on('scss-error', (_, err) => { + this.error = err; + this.$forceUpdate(); + if (err) + console.error('SCSS parse error:', err); + }); + }, + methods: { + save() { + const scss = this.codemirror.getValue(); + BDIpc.sendToDiscord('save-scss', scss); + }, + update() { + const scss = this.codemirror.getValue(); + BDIpc.sendToDiscord('update-scss', scss); + }, + toggleaot() { + this.alwaysOnTop = !this.alwaysOnTop; + remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop); + }, + close() { + window.close(); + }, + setScss(scss) { + this.loading = false; + this.codemirror.setValue(scss || ''); + }, + cmOnChange(value) { + if(this.liveUpdate) BDIpc.sendToDiscord('update-scss', value); + }, + cmOnKeyUp(editor, event) { + if (event.ctrlKey) return; + if (ExcludedIntelliSenseTriggerKeys[event.keyCode]) return; + cmCommands.autocomplete(editor, null, { completeSingle: false }); + }, + toggleLiveUpdate(e) { + this.liveUpdate = !this.liveUpdate; + } } } diff --git a/csseditor/src/index.js b/csseditor/src/index.js index 496518e6..9146bd05 100644 --- a/csseditor/src/index.js +++ b/csseditor/src/index.js @@ -1,15 +1,21 @@ -const styles = require('./styles/index.scss'); +// const styles = require('./styles/index.scss'); import Vue from 'vue'; +import VueCodemirror from 'vue-codemirror'; + import Editor from './Editor.vue'; -import VueCodemirror from 'vue-codemirror' +import styles from './styles/index.scss'; Vue.use(VueCodemirror, {}); window.cmCommands = VueCodemirror.CodeMirror.commands; -new Vue({ - el: '#root', +const mount = document.createElement('div'); +mount.classList.add('container'); +document.body.appendChild(mount); + +const vue = new Vue({ + el: mount, components: { Editor }, template: '' }); diff --git a/csseditor/src/styles/tools.scss b/csseditor/src/styles/tools.scss index d2fc3c16..0c534bc6 100644 --- a/csseditor/src/styles/tools.scss +++ b/csseditor/src/styles/tools.scss @@ -1,3 +1,13 @@ +.parser-error { + padding: 4px 6px; + background: #292b2f; + border-top: 1px solid hsla(218,5%,47%,.3); + color: #d84040; + font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif; + white-space: pre-wrap; + font-size: 12px; +} + .tools { height: 36px; background: #292b2f; @@ -24,16 +34,18 @@ cursor: pointer; border: 0; margin-right: 4px; + flex: 0 0 auto; &:hover { background: #44474e; - color: #FFF; + color: #fff; } } #chkboxLiveUpdate { padding: 3px 10px; line-height: 22px; + flex: 0 0 auto; input[type="checkbox"] { margin: 0 6px 0 0; diff --git a/csseditor/webpack.config.js b/csseditor/webpack.config.js index affb1609..0e7ff99d 100644 --- a/csseditor/webpack.config.js +++ b/csseditor/webpack.config.js @@ -26,4 +26,4 @@ module.exports = { vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js') } } -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index 01f428c9..74631cef 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "build": "npm run build --prefix client && npm run build --prefix core && npm run build --prefix csseditor", "watch_client": "npm run watch --prefix client", "watch_core": "npm run watch --prefix core", + "watch_csseditor": "npm run watch --prefix csseditor", "lint": "eslint -f unix client/src core/src csseditor/src", "test": "npm run build && npm run lint", "build_node-sass": "node scripts/build-node-sass.js"