CSS editor improvements
This commit is contained in:
parent
976aecd8f2
commit
91275f4332
|
@ -76,6 +76,32 @@
|
|||
"headertext": "Emote Settings",
|
||||
"settings": []
|
||||
},
|
||||
{
|
||||
"id": "css",
|
||||
"text": "CSS Editor",
|
||||
"hidden": true,
|
||||
"settings": [
|
||||
{
|
||||
"category": "default",
|
||||
"settings": [
|
||||
{
|
||||
"id": "live-update",
|
||||
"type": "bool",
|
||||
"text": "Live update",
|
||||
"hint": "Automatically recompile custom CSS when typing in the custom CSS editor.",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"id": "watch-files",
|
||||
"type": "bool",
|
||||
"text": "Watch included files",
|
||||
"hint": "Automatically recompile theme and custom CSS when a file it imports is changed.",
|
||||
"value": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "security",
|
||||
"text": "Security",
|
||||
|
|
|
@ -195,7 +195,7 @@ export default class {
|
|||
userConfig.enabled = readUserConfig.enabled || false;
|
||||
userConfig.config.merge({ settings: readUserConfig.config });
|
||||
userConfig.config.setSaved();
|
||||
userConfig.data = readUserConfig.data || undefined;
|
||||
userConfig.data = readUserConfig.data || {};
|
||||
} catch (err) { /*We don't care if this fails it either means that user config doesn't exist or there's something wrong with it so we revert to default config*/
|
||||
console.info(`Failed reading config for ${this.contentType} ${readConfig.info.name} in ${dirName}`);
|
||||
console.error(err);
|
||||
|
|
|
@ -8,20 +8,33 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import { ClientIPC } from 'common';
|
||||
import { FileUtils, ClientLogger as Logger, ClientIPC } from 'common';
|
||||
import Settings from './settings';
|
||||
import { DOM } from 'ui';
|
||||
import filewatcher from 'filewatcher';
|
||||
import path from 'path';
|
||||
import electron from 'electron';
|
||||
|
||||
/**
|
||||
* Custom css editor communications
|
||||
*/
|
||||
export default class {
|
||||
export default new class {
|
||||
|
||||
constructor() {
|
||||
this._scss = '';
|
||||
this._css = '';
|
||||
this._error = undefined;
|
||||
this.editor_bounds = undefined;
|
||||
this._files = undefined;
|
||||
this._filewatcher = undefined;
|
||||
this._watchfiles = undefined;
|
||||
this.compiling = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init css editor
|
||||
*/
|
||||
static init() {
|
||||
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-save-csseditor-bounds', (e, bounds) => this.saveEditorBounds(bounds));
|
||||
|
@ -31,17 +44,25 @@ export default class {
|
|||
await this.save();
|
||||
});
|
||||
|
||||
this.filewatcher = filewatcher();
|
||||
this.filewatcher.on('change', (file, stat) => {
|
||||
// Recompile SCSS
|
||||
this.updateScss(this.scss);
|
||||
this.liveupdate = Settings.getSetting('css', 'default', 'live-update');
|
||||
this.liveupdate.on('setting-updated', event => {
|
||||
this.sendToEditor('set-liveupdate', event.value);
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-get-liveupdate', () => this.sendToEditor('set-liveupdate', this.liveupdate.value));
|
||||
ClientIPC.on('bd-set-liveupdate', (e, value) => this.liveupdate.value = value);
|
||||
|
||||
this.watchfilessetting = Settings.getSetting('css', 'default', 'watch-files');
|
||||
this.watchfilessetting.on('setting-updated', event => {
|
||||
if (event.value) this.watchfiles = this.files;
|
||||
else this.watchfiles = [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show css editor, flashes if already visible
|
||||
*/
|
||||
static async show() {
|
||||
async show() {
|
||||
await ClientIPC.send('openCssEditor', this.editor_bounds);
|
||||
}
|
||||
|
||||
|
@ -50,34 +71,35 @@ export default class {
|
|||
* @param {String} scss scss to compile
|
||||
* @param {bool} sendSource send to css editor instance
|
||||
*/
|
||||
static updateScss(scss, sendSource) {
|
||||
async updateScss(scss, sendSource) {
|
||||
if (sendSource)
|
||||
this.sendToEditor('set-scss', { scss });
|
||||
|
||||
if (!scss) {
|
||||
this._scss = this.css = '';
|
||||
this.sendToEditor('scss-error', null);
|
||||
return Promise.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.compile(scss).then(result => {
|
||||
this.css = result.css.toString();
|
||||
this._scss = scss;
|
||||
this.files = result.stats.includedFiles;
|
||||
this.sendToEditor('scss-error', null);
|
||||
resolve();
|
||||
}).catch(err => {
|
||||
this.sendToEditor('scss-error', err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
try {
|
||||
this.compiling = true;
|
||||
const result = await this.compile(scss);
|
||||
this.css = result.css.toString();
|
||||
this._scss = scss;
|
||||
this.files = result.stats.includedFiles;
|
||||
this.error = null;
|
||||
this.compiling = false;
|
||||
} catch (err) {
|
||||
this.compiling = false;
|
||||
this.error = err;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save css to file
|
||||
*/
|
||||
static async save() {
|
||||
async save() {
|
||||
Settings.saveSettings();
|
||||
}
|
||||
|
||||
|
@ -85,7 +107,7 @@ export default class {
|
|||
* Save current editor bounds
|
||||
* @param {Rectangle} bounds editor bounds
|
||||
*/
|
||||
static saveEditorBounds(bounds) {
|
||||
saveEditorBounds(bounds) {
|
||||
this.editor_bounds = bounds;
|
||||
Settings.saveSettings();
|
||||
}
|
||||
|
@ -94,70 +116,192 @@ export default class {
|
|||
* Send scss to core for compilation
|
||||
* @param {String} scss scss string
|
||||
*/
|
||||
static async compile(scss) {
|
||||
const result = await ClientIPC.send('bd-compileSass', { data: scss });
|
||||
console.log('Custom CSS SCSS compiler result:', result, '- CSS:', result.css.toString());
|
||||
return result;
|
||||
async compile(scss) {
|
||||
return await ClientIPC.send('bd-compileSass', {
|
||||
data: scss,
|
||||
path: await this.fileExists() ? this.filePath : undefined
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send css to open editor
|
||||
* Recompile the current SCSS
|
||||
* @return {Promise}
|
||||
*/
|
||||
async recompile() {
|
||||
return await this.updateScss(this.scss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data to open editor
|
||||
* @param {any} channel
|
||||
* @param {any} data
|
||||
*/
|
||||
static async sendToEditor(channel, data) {
|
||||
async sendToEditor(channel, data) {
|
||||
return await ClientIPC.send('sendToCssEditor', { channel, data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an SCSS file in a system editor
|
||||
*/
|
||||
async openSystemEditor() {
|
||||
try {
|
||||
await FileUtils.fileExists(this.filePath);
|
||||
} catch (err) {
|
||||
// File doesn't exist
|
||||
// Create it
|
||||
await FileUtils.writeFile(this.filePath, '');
|
||||
}
|
||||
|
||||
Logger.log('CSS Editor', `Opening file ${this.filePath} in the user's default editor.`);
|
||||
|
||||
// For some reason this doesn't work
|
||||
// if (!electron.shell.openItem(this.filePath))
|
||||
if (!electron.shell.openExternal('file://' + this.filePath))
|
||||
throw {message: 'Failed to open system editor.'};
|
||||
}
|
||||
|
||||
/** Set current state
|
||||
* @param {String} scss Current uncompiled SCSS
|
||||
* @param {String} css Current compiled CSS
|
||||
* @param {String} files Files imported in the SCSS
|
||||
* @param {String} err Current compiler error
|
||||
*/
|
||||
setState(scss, css, files, err) {
|
||||
this._scss = scss;
|
||||
this.sendToEditor('set-scss', { scss });
|
||||
this.css = css;
|
||||
this.files = files;
|
||||
this.error = err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current uncompiled scss
|
||||
*/
|
||||
static get scss() {
|
||||
get scss() {
|
||||
return this._scss || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current scss
|
||||
*/
|
||||
static set scss(scss) {
|
||||
set scss(scss) {
|
||||
this.updateScss(scss, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current compiled css
|
||||
*/
|
||||
get css() {
|
||||
return this._css || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject compiled css to head
|
||||
* {DOM}
|
||||
*/
|
||||
static set css(css) {
|
||||
set css(css) {
|
||||
this._css = css;
|
||||
DOM.injectStyle(css, 'bd-customcss');
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of files that are being watched for changes.
|
||||
* @returns {Array} Files being watched
|
||||
* Current error
|
||||
*/
|
||||
static get files() {
|
||||
get error() {
|
||||
return this._error || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current error
|
||||
* {DOM}
|
||||
*/
|
||||
set error(err) {
|
||||
this._error = err;
|
||||
this.sendToEditor('scss-error', err);
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of files that are imported in custom CSS.
|
||||
* @return {Array} Files being watched
|
||||
*/
|
||||
get files() {
|
||||
return this._files || (this._files = []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all files that are imported in custom CSS.
|
||||
* @param {Array} files Files to watch
|
||||
*/
|
||||
set files(files) {
|
||||
this._files = files;
|
||||
if (Settings.get('css', 'default', 'watch-files'))
|
||||
this.watchfiles = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* A filewatcher instance.
|
||||
*/
|
||||
get filewatcher() {
|
||||
if (this._filewatcher) return this._filewatcher;
|
||||
this._filewatcher = filewatcher();
|
||||
this._filewatcher.on('change', (file, stat) => {
|
||||
// Recompile SCSS
|
||||
this.recompile();
|
||||
});
|
||||
return this._filewatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of files that are being watched for changes.
|
||||
* @return {Array} Files being watched
|
||||
*/
|
||||
get watchfiles() {
|
||||
return this._watchfiles || (this._watchfiles = []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all files to be watched.
|
||||
* @param {Array} files Files to watch
|
||||
*/
|
||||
static set files(files) {
|
||||
set watchfiles(files) {
|
||||
for (let file of files) {
|
||||
if (!this.files.includes(file)) {
|
||||
if (!this.watchfiles.includes(file)) {
|
||||
this.filewatcher.add(file);
|
||||
this.files.push(file);
|
||||
this.watchfiles.push(file);
|
||||
Logger.log('CSS Editor', `Watching file ${file} for changes`);
|
||||
}
|
||||
}
|
||||
|
||||
for (let index in this.files) {
|
||||
const file = this.files[index];
|
||||
if (!files.includes(file)) {
|
||||
for (let index in this.watchfiles) {
|
||||
let file = this.watchfiles[index];
|
||||
while (file && !files.find(f => f === file)) {
|
||||
this.filewatcher.remove(file);
|
||||
this.files.splice(index, 1);
|
||||
this.watchfiles.splice(index, 1);
|
||||
Logger.log('CSS Editor', `No longer watching file ${file} for changes`);
|
||||
file = this.watchfiles[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The path of the file the system editor should save to.
|
||||
* @return {String}
|
||||
*/
|
||||
get filePath() {
|
||||
return path.join(Settings.dataPath, 'user.scss');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the system editor's file exists.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
async fileExists() {
|
||||
try {
|
||||
await FileUtils.fileExists(this.filePath);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ export default class ExtModule {
|
|||
get dirName() { return this.paths.dirName }
|
||||
get enabled() { return true }
|
||||
get config() { return this.userConfig.config || [] }
|
||||
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
|
||||
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new ExtModuleEvents(this)) }
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ export default class Plugin {
|
|||
get settings() { return this.userConfig.config }
|
||||
get config() { return this.settings.settings }
|
||||
get pluginConfig() { return this.config }
|
||||
get data() { return this.userConfig.data }
|
||||
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
|
||||
get exports() { return this._exports ? this._exports : (this._exports = this.getExports()) }
|
||||
get events() { return this.EventEmitter ? this.EventEmitter : (this.EventEmitter = new PluginEvents(this)) }
|
||||
|
||||
|
|
|
@ -105,6 +105,9 @@ export default class PluginApi {
|
|||
getConfigAsSCSS(settingsset) {
|
||||
return ThemeManager.getConfigAsSCSS(settingsset ? settingsset : this.plugin.settings);
|
||||
}
|
||||
getConfigAsSCSSMap(settingsset) {
|
||||
return ThemeManager.getConfigAsSCSSMap(settingsset ? settingsset : this.plugin.settings);
|
||||
}
|
||||
injectStyle(id, css) {
|
||||
if (id && !css) css = id, id = undefined;
|
||||
this.deleteStyle(id);
|
||||
|
@ -132,6 +135,7 @@ export default class PluginApi {
|
|||
return {
|
||||
compileSass: this.compileSass.bind(this),
|
||||
getConfigAsSCSS: this.getConfigAsSCSS.bind(this),
|
||||
getConfigAsSCSSMap: this.getConfigAsSCSSMap.bind(this),
|
||||
injectStyle: this.injectStyle.bind(this),
|
||||
injectSass: this.injectSass.bind(this),
|
||||
deleteStyle: this.deleteStyle.bind(this),
|
||||
|
|
|
@ -27,7 +27,7 @@ export default new class Settings {
|
|||
|
||||
const settingsPath = path.resolve(this.dataPath, 'user.settings.json');
|
||||
const user_config = await FileUtils.readJsonFromFile(settingsPath);
|
||||
const { settings, scss, css_editor_bounds, css_editor_files } = user_config;
|
||||
const { settings, scss, css, css_editor_files, scss_error, css_editor_bounds } = user_config;
|
||||
|
||||
this.settings = defaultSettings.map(set => {
|
||||
const newSet = new SettingsSet(set);
|
||||
|
@ -46,9 +46,8 @@ export default new class Settings {
|
|||
return newSet;
|
||||
});
|
||||
|
||||
CssEditor.updateScss(scss, true);
|
||||
CssEditor.setState(scss, css, css_editor_files, scss_error);
|
||||
CssEditor.editor_bounds = css_editor_bounds || {};
|
||||
CssEditor.files = css_editor_files || [];
|
||||
} catch (err) {
|
||||
// There was an error loading settings
|
||||
// This probably means that the user doesn't have any settings yet
|
||||
|
@ -64,13 +63,15 @@ export default new class Settings {
|
|||
await FileUtils.writeJsonToFile(settingsPath, {
|
||||
settings: this.settings.map(set => set.strip()),
|
||||
scss: CssEditor.scss,
|
||||
css: CssEditor.css,
|
||||
css_editor_files: CssEditor.files,
|
||||
scss_error: CssEditor.error,
|
||||
css_editor_bounds: {
|
||||
width: CssEditor.editor_bounds.width,
|
||||
height: CssEditor.editor_bounds.height,
|
||||
x: CssEditor.editor_bounds.x,
|
||||
y: CssEditor.editor_bounds.y
|
||||
},
|
||||
css_editor_files: CssEditor.files
|
||||
}
|
||||
});
|
||||
|
||||
for (let set of this.getSettings) {
|
||||
|
@ -90,6 +91,7 @@ export default new class Settings {
|
|||
get core() { return this.getSet('core') }
|
||||
get ui() { return this.getSet('ui') }
|
||||
get emotes() { return this.getSet('emotes') }
|
||||
get css() { return this.getSet('css') }
|
||||
get security() { return this.getSet('security') }
|
||||
|
||||
getCategory(set_id, category_id) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import Settings from './settings';
|
||||
import ThemeManager from './thememanager';
|
||||
import { EventEmitter } from 'events';
|
||||
import { SettingUpdatedEvent, SettingsUpdatedEvent } from 'structs';
|
||||
|
@ -47,13 +48,11 @@ export default class Theme {
|
|||
this.settings.on('settings-updated', event => this.events.emit('settings-updated', event));
|
||||
this.settings.on('settings-updated', event => this.recompile());
|
||||
|
||||
this.filewatcher = filewatcher();
|
||||
const files = this.files;
|
||||
this.data.files = [];
|
||||
this.files = files;
|
||||
this.filewatcher.on('change', (file, stat) => {
|
||||
// Recompile SCSS
|
||||
this.recompile();
|
||||
const watchfiles = Settings.getSetting('css', 'default', 'watch-files');
|
||||
if (watchfiles.value) this.watchfiles = this.files;
|
||||
watchfiles.on('setting-updated', event => {
|
||||
if (event.value) this.watchfiles = this.files;
|
||||
else this.watchfiles = [];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -166,34 +165,64 @@ export default class Theme {
|
|||
}
|
||||
|
||||
/**
|
||||
* An array of files that are being watched for changes.
|
||||
* @returns {Array} Files being watched
|
||||
* An array of files that are imported in custom CSS.
|
||||
* @return {Array} Files being watched
|
||||
*/
|
||||
get files() {
|
||||
return this.data.files || (this.data.files = []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all files to be watched.
|
||||
* Sets all files that are imported in custom CSS.
|
||||
* @param {Array} files Files to watch
|
||||
*/
|
||||
set files(files) {
|
||||
if (!files) files = [];
|
||||
this.data.files = files;
|
||||
if (Settings.get('css', 'default', 'watch-files'))
|
||||
this.watchfiles = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* A filewatcher instance.
|
||||
*/
|
||||
get filewatcher() {
|
||||
if (this._filewatcher) return this._filewatcher;
|
||||
this._filewatcher = filewatcher();
|
||||
this._filewatcher.on('change', (file, stat) => {
|
||||
// Recompile SCSS
|
||||
this.recompile();
|
||||
});
|
||||
return this._filewatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* An array of files that are being watched for changes.
|
||||
* @return {Array} Files being watched
|
||||
*/
|
||||
get watchfiles() {
|
||||
return this._watchfiles || (this._watchfiles = []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all files to be watched.
|
||||
* @param {Array} files Files to watch
|
||||
*/
|
||||
set watchfiles(files) {
|
||||
for (let file of files) {
|
||||
if (!this.files.includes(file)) {
|
||||
if (!this.watchfiles.includes(file)) {
|
||||
this.filewatcher.add(file);
|
||||
this.files.push(file);
|
||||
this.watchfiles.push(file);
|
||||
Logger.log(this.name, `Watching file ${file} for changes`);
|
||||
}
|
||||
}
|
||||
|
||||
for (let index in this.files) {
|
||||
const file = this.files[index];
|
||||
if (!files.includes(file)) {
|
||||
for (let index in this.watchfiles) {
|
||||
let file = this.watchfiles[index];
|
||||
while (file && !files.find(f => f === file)) {
|
||||
this.filewatcher.remove(file);
|
||||
this.files.splice(index, 1);
|
||||
this.watchfiles.splice(index, 1);
|
||||
Logger.log(this.name, `No longer watching file ${file} for changes`);
|
||||
file = this.watchfiles[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ export default class SettingsSet {
|
|||
return this.args.headertext || `${this.text} Settings`;
|
||||
}
|
||||
|
||||
get hidden() {
|
||||
return this.args.hidden || false;
|
||||
}
|
||||
|
||||
get categories() {
|
||||
return this.args.settings || [];
|
||||
}
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
|
||||
.bd-hint {
|
||||
flex: 1 1 auto;
|
||||
color: #72767d;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
line-height: 20px;
|
||||
border-bottom: 0px solid rgba(114, 118, 126, 0.1);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
.bd-err {
|
||||
color: $colerr;
|
||||
}
|
||||
|
||||
.bd-p {
|
||||
color: $coldimwhite;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.bd-hint {
|
||||
@extend .bd-p;
|
||||
color: #72767d;
|
||||
}
|
|
@ -10,3 +10,4 @@
|
|||
@import './profilebadges.scss';
|
||||
|
||||
@import './discordoverrides.scss';
|
||||
@import './helpers.scss';
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<ContentColumn slot="content">
|
||||
<div v-for="set in Settings.settings" v-if="activeContent(set.id) || animatingContent(set.id)" :class="{active: activeContent(set.id), animating: animatingContent(set.id)}">
|
||||
<div v-for="set in Settings.settings" v-if="!set.hidden && activeContent(set.id) || animatingContent(set.id)" :class="{active: activeContent(set.id), animating: animatingContent(set.id)}">
|
||||
<SettingsWrapper :headertext="set.headertext">
|
||||
<SettingsPanel :settings="set" :schemes="set.schemes" />
|
||||
</SettingsWrapper>
|
||||
|
|
|
@ -11,58 +11,97 @@
|
|||
<template>
|
||||
<SettingsWrapper headertext="CSS Editor">
|
||||
<div class="bd-css-editor">
|
||||
<div v-if="CssEditor.error" class="bd-form-item">
|
||||
<h5 style="margin-bottom: 10px;">Compiler error</h5>
|
||||
<div class="bd-err bd-pre-wrap"><div class="bd-pre">{{ CssEditor.error.formatted }}</div></div>
|
||||
<div class="bd-form-divider"></div>
|
||||
</div>
|
||||
|
||||
<div class="bd-form-item">
|
||||
<h5>Custom Editor</h5>
|
||||
<div class="bd-form-warning">
|
||||
<div class="bd-text">Custom Editor is not installed!</div>
|
||||
<FormButton>Install</FormButton>
|
||||
</div>
|
||||
<span style="color: #FFF; font-size: 12px; font-weight: 700;">*This is displayed if editor is not installed</span>
|
||||
<FormButton :onClick="openInternalEditor">Open</FormButton>
|
||||
<FormButton v-if="internalEditorIsInstalled" :onClick="openInternalEditor">Open</FormButton>
|
||||
<template v-else>
|
||||
<div class="bd-form-warning">
|
||||
<div class="bd-text">Custom Editor is not installed!</div>
|
||||
<FormButton>Install</FormButton>
|
||||
</div>
|
||||
<span style="color: #fff; font-size: 12px; font-weight: 700;">* This is displayed if editor is not installed</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<Setting :setting="liveUpdateSetting" :change="enabled => liveUpdateSetting.value = enabled" />
|
||||
|
||||
<div class="bd-form-item">
|
||||
<h5>System Editor</h5>
|
||||
<FormButton>
|
||||
Open
|
||||
</FormButton>
|
||||
<FormButton :onClick="openSystemEditor">Open</FormButton>
|
||||
<p class="bd-hint">This will open {{ systemEditorPath }} in your system's default editor.</p>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<FormButton :onClick="() => {}">Enabled</FormButton>
|
||||
<FormButton :disabled="true"><span>Disabled</span></FormButton>
|
||||
<FormButton :loading="true" />
|
||||
|
||||
<div class="bd-form-item">
|
||||
<h5 style="margin-bottom: 10px;">Settings</h5>
|
||||
</div>
|
||||
<SettingsPanel :settings="settingsset" />
|
||||
|
||||
<!-- <Setting :setting="liveUpdateSetting" />
|
||||
<Setting :setting="watchFilesSetting" /> -->
|
||||
|
||||
<FormButton :onClick="recompile" :loading="compiling">Recompile</FormButton>
|
||||
</div>
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { CssEditor } from 'modules';
|
||||
import { Settings, CssEditor } from 'modules';
|
||||
import { SettingsWrapper } from './';
|
||||
import { FormButton } from '../common';
|
||||
import SettingsPanel from './SettingsPanel.vue';
|
||||
import Setting from './setting/Setting.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsWrapper,
|
||||
SettingsPanel,
|
||||
Setting,
|
||||
FormButton
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
liveUpdateSetting: {
|
||||
id: "live-update",
|
||||
type: "bool",
|
||||
text: "Live Update",
|
||||
hint: "Automatically update client css when saved.",
|
||||
value: true
|
||||
}
|
||||
CssEditor
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
error() {
|
||||
return this.CssEditor.error;
|
||||
},
|
||||
compiling() {
|
||||
return this.CssEditor.compiling;
|
||||
},
|
||||
systemEditorPath() {
|
||||
return this.CssEditor.filePath;
|
||||
},
|
||||
liveUpdateSetting() {
|
||||
return Settings.getSetting('css', 'default', 'live-update');
|
||||
},
|
||||
watchFilesSetting() {
|
||||
return Settings.getSetting('css', 'default', 'watch-files');
|
||||
},
|
||||
settingsset() {
|
||||
return Settings.css;
|
||||
},
|
||||
internalEditorIsInstalled() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openInternalEditor() {
|
||||
CssEditor.show();
|
||||
this.CssEditor.show();
|
||||
},
|
||||
openSystemEditor() {
|
||||
this.CssEditor.openSystemEditor();
|
||||
},
|
||||
recompile() {
|
||||
this.CssEditor.recompile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,33 +116,39 @@ export default class DOM {
|
|||
return document.querySelector(e);
|
||||
}
|
||||
|
||||
static getElements(e) {
|
||||
return document.querySelectorAll(e);
|
||||
}
|
||||
|
||||
static createElement(tag = 'div', className = null, id = null) {
|
||||
return new BdNode(tag, className, id);
|
||||
}
|
||||
|
||||
static deleteStyle(id) {
|
||||
const exists = this.getElement(`bd-styles > #${id}`);
|
||||
const exists = Array.from(this.bdStyles.children).find(e => e.id === id);
|
||||
if (exists) exists.remove();
|
||||
}
|
||||
|
||||
static injectStyle(css, id) {
|
||||
this.deleteStyle(id);
|
||||
this.bdStyles.append(this.createStyle(css, id));
|
||||
const style = Array.from(this.bdStyles.children).find(e => e.id === id) || this.createElement('style', null, id).element;
|
||||
style.textContent = css;
|
||||
this.bdStyles.append(style);
|
||||
}
|
||||
|
||||
static getStyleCss(id) {
|
||||
const exists = this.getElement(`bd-styles > #${id}`);
|
||||
const exists = this.bdStyles.children.find(e => e.id === id);
|
||||
return exists ? exists.textContent : '';
|
||||
}
|
||||
|
||||
static deleteTheme(id) {
|
||||
const exists = this.getElement(`bd-themes > #${id}`);
|
||||
const exists = Array.from(this.bdThemes.children).find(e => e.id === id);
|
||||
if (exists) exists.remove();
|
||||
}
|
||||
|
||||
static injectTheme(css, id) {
|
||||
this.deleteTheme(id);
|
||||
this.bdThemes.append(this.createStyle(css, id));
|
||||
const style = Array.from(this.bdThemes.children).find(e => e.id === id) || this.createElement('style', null, id).element;
|
||||
style.textContent = css;
|
||||
this.bdThemes.append(style);
|
||||
}
|
||||
|
||||
static createStyle(css, id) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<button @click="update">Update</button>
|
||||
<div class="flex-spacer"></div>
|
||||
<div id="chkboxLiveUpdate">
|
||||
<input type="checkbox" @click="toggleLiveUpdate" :checked="liveUpdate" /><span>Live Update</span>
|
||||
<label><input type="checkbox" @click="toggleLiveUpdate" v-model="liveUpdate" /><span>Live Update</span></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -130,8 +130,7 @@
|
|||
return this.$refs.mycm;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.codemirror.on('keyup', this.cmOnKeyUp);
|
||||
created() {
|
||||
BDIpc.on('set-scss', (_, data) => {
|
||||
if (data.error) {
|
||||
console.log(data.error);
|
||||
|
@ -141,14 +140,24 @@
|
|||
this.setScss(data.scss);
|
||||
});
|
||||
|
||||
BDIpc.sendToDiscord('get-scss');
|
||||
|
||||
BDIpc.on('scss-error', (_, err) => {
|
||||
this.error = err;
|
||||
this.$forceUpdate();
|
||||
if (err)
|
||||
console.error('SCSS parse error:', err);
|
||||
});
|
||||
|
||||
BDIpc.on('set-liveupdate', (e, liveUpdate) => this.liveUpdate = liveUpdate);
|
||||
},
|
||||
mounted() {
|
||||
this.codemirror.on('keyup', this.cmOnKeyUp);
|
||||
BDIpc.sendToDiscord('get-scss');
|
||||
BDIpc.sendToDiscord('get-liveupdate');
|
||||
},
|
||||
watch: {
|
||||
liveUpdate(liveUpdate) {
|
||||
BDIpc.sendToDiscord('set-liveupdate', liveUpdate);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
|
|
|
@ -38,11 +38,10 @@
|
|||
width: 25px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
/*background: #263238;*/
|
||||
background: #36393f;
|
||||
color: #bac9d2;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
transition: background-color .2s ease;
|
||||
transition: background-color .2s ease, color .2s ease;
|
||||
cursor: default;
|
||||
border: 0;
|
||||
height: 25px;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
background: #292b2f;
|
||||
border-top: 1px solid hsla(218,5%,47%,.3);
|
||||
color: #d84040;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
|||
background: #36393f;
|
||||
color: #bac9d2;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
transition: background-color .2s ease;
|
||||
transition: background-color .2s ease, color .2s ease;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
margin-right: 4px;
|
||||
|
@ -47,6 +47,10 @@
|
|||
line-height: 22px;
|
||||
flex: 0 0 auto;
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin: 0 6px 0 0;
|
||||
cursor: pointer;
|
||||
|
@ -57,7 +61,6 @@
|
|||
font-weight: 500;
|
||||
color: #bac9d2;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue