commit
f4b7c99c31
|
@ -12,3 +12,4 @@ user.config.json
|
|||
/.vs
|
||||
/npm-debug.log
|
||||
/tests/ext/extensions
|
||||
/tests/userdata
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
|
||||
import BdCss from './styles/index.scss';
|
||||
import { Events, CssEditor, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
|
||||
import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
|
||||
import { ClientLogger as Logger, ClientIPC, Utils } from 'common';
|
||||
import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin';
|
||||
import electron from 'electron';
|
||||
|
@ -18,7 +18,7 @@ import path from 'path';
|
|||
import { setTimeout } from 'timers';
|
||||
|
||||
const tests = typeof PRODUCTION === 'undefined';
|
||||
const ignoreExternal = false;
|
||||
const ignoreExternal = true;
|
||||
|
||||
class BetterDiscord {
|
||||
|
||||
|
@ -30,7 +30,7 @@ class BetterDiscord {
|
|||
this._bd = {
|
||||
DOM, BdUI, BdMenu, Modals, Reflection, Toasts, Notifications, BdContextMenu, DiscordContextMenu,
|
||||
|
||||
Events, CssEditor, Globals, Settings, Database, Updater,
|
||||
Events, Globals, Settings, Database, Updater,
|
||||
ModuleManager, PluginManager, ThemeManager, ExtModuleManager, PackageInstaller,
|
||||
Vendor,
|
||||
|
||||
|
|
|
@ -38,6 +38,14 @@ export default new class {
|
|||
ClientIPC.on('bd-get-scss', () => this.scss, true);
|
||||
ClientIPC.on('bd-update-scss', (e, scss) => this.updateScss(scss));
|
||||
ClientIPC.on('bd-save-csseditor-bounds', (e, bounds) => this.saveEditorBounds(bounds));
|
||||
ClientIPC.on('bd-editor-runScript', (e, script) => {
|
||||
try {
|
||||
new Function(script)();
|
||||
e.reply('ok');
|
||||
} catch (err) {
|
||||
e.reply({ err: err.stack || err });
|
||||
}
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-save-scss', async (e, scss) => {
|
||||
await this.updateScss(scss);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* BetterDiscord Editor Module
|
||||
* 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 Module from './imodule';
|
||||
import { DOM } from 'ui';
|
||||
|
||||
export default new class extends Module {
|
||||
|
||||
get name() { return 'Editor' }
|
||||
get delay() { return false; }
|
||||
|
||||
setInitialState(state) {
|
||||
return {
|
||||
editorBounds: undefined
|
||||
};
|
||||
}
|
||||
|
||||
initialize() {
|
||||
super.initialize();
|
||||
(async () => {
|
||||
try {
|
||||
// TODO this is temporary
|
||||
const userScss = await this.send('readDataFile', 'user.scss');
|
||||
const compiled = await this.send('compileSass', { data: userScss });
|
||||
this.injectStyle('customcss', compiled.css.toString());
|
||||
} catch (err) {
|
||||
console.warn('SCSS Compilation error', err);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
events(ipc) {
|
||||
ipc.on('editor-runScript', (e, script) => {
|
||||
try {
|
||||
new Function(script)();
|
||||
e.reply('ok');
|
||||
} catch (err) {
|
||||
e.reply({ err: err.stack || err });
|
||||
}
|
||||
});
|
||||
|
||||
ipc.on('editor-injectStyle', (e, { id, style }) => {
|
||||
this.injectStyle(id, style);
|
||||
e.reply('ok');
|
||||
});
|
||||
}
|
||||
|
||||
injectStyle(id, style) {
|
||||
return DOM.injectStyle(style, `userstyle-${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show editor, flashes if already visible.
|
||||
*/
|
||||
async show() {
|
||||
await this.send('editor-open', this.state.editorBounds);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* BetterDiscord Module Base
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base Module that every non-static module should extend
|
||||
*/
|
||||
|
||||
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||
|
||||
export default class Module {
|
||||
|
||||
constructor(args) {
|
||||
this.__ = {
|
||||
state: args || {},
|
||||
args
|
||||
};
|
||||
this.setState = this.setState.bind(this);
|
||||
|
||||
if (this.delay) { // If delay is set then module is set to load delayed from modulemanager
|
||||
this.initialize = this.initialize.bind(this);
|
||||
this.init = this.initialize;
|
||||
} else {
|
||||
this.initialize();
|
||||
this.init = () => { };
|
||||
}
|
||||
}
|
||||
|
||||
initialize() {
|
||||
if (this.bindings) this.bindings();
|
||||
if (this.setInitialState) this.setState(this.setInitialState(this.state));
|
||||
if (this.events) this.events(ClientIPC);
|
||||
}
|
||||
|
||||
setState(newState) {
|
||||
const oldState = this.state;
|
||||
Object.assign(this.state, newState);
|
||||
if (this.stateChanged) this.stateChanged(oldState, newState);
|
||||
}
|
||||
|
||||
set args(t) { }
|
||||
get args() { return this.__.args; }
|
||||
|
||||
set state(state) { return this.__.state = state; }
|
||||
get state() { return this.__.state; }
|
||||
|
||||
async send(channel, message) {
|
||||
return ClientIPC.send(channel, message);
|
||||
}
|
||||
|
||||
log(msg) {
|
||||
Logger.log(this.name, msg);
|
||||
}
|
||||
|
||||
warn(msg) {
|
||||
Logger.log(this.name, msg);
|
||||
}
|
||||
|
||||
err(msg) {
|
||||
Logger.log(this.name, msg);
|
||||
}
|
||||
|
||||
info(msg) {
|
||||
Logger.log(this.name, msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
import { ClientLogger as Logger } from 'common';
|
||||
import { SocketProxy, EventHook, CssEditor } from 'modules';
|
||||
import { SocketProxy, EventHook } from 'modules';
|
||||
import { ProfileBadges, ClassNormaliser } from 'ui';
|
||||
import Updater from './updater';
|
||||
|
||||
|
@ -27,7 +27,6 @@ export default class {
|
|||
new ClassNormaliser(),
|
||||
new SocketProxy(),
|
||||
new EventHook(),
|
||||
CssEditor,
|
||||
Updater
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export { default as Events } from './events';
|
||||
export { default as CssEditor } from './csseditor';
|
||||
export { default as Editor } from './editor';
|
||||
export { default as Globals } from './globals';
|
||||
export { default as Settings } from './settings';
|
||||
export { default as Database } from './database';
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
// TODO this should be remade as editor instead of css editor
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="CSS Editor">
|
||||
<div class="bd-cssEditor">
|
||||
|
@ -49,7 +51,7 @@
|
|||
|
||||
<script>
|
||||
// Imports
|
||||
import { Settings, CssEditor } from 'modules';
|
||||
import { Settings, Editor } from 'modules';
|
||||
import { SettingsWrapper } from './';
|
||||
import { FormButton } from '../common';
|
||||
import SettingsPanel from './SettingsPanel.vue';
|
||||
|
@ -64,18 +66,18 @@
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
CssEditor
|
||||
Editor
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
error() {
|
||||
return this.CssEditor.error;
|
||||
return this.Editor.error;
|
||||
},
|
||||
compiling() {
|
||||
return this.CssEditor.compiling;
|
||||
return this.Editor.compiling;
|
||||
},
|
||||
systemEditorPath() {
|
||||
return this.CssEditor.filePath;
|
||||
return this.Editor.filePath;
|
||||
},
|
||||
liveUpdateSetting() {
|
||||
return Settings.getSetting('css', 'default', 'live-update');
|
||||
|
@ -92,13 +94,13 @@
|
|||
},
|
||||
methods: {
|
||||
openInternalEditor() {
|
||||
this.CssEditor.show();
|
||||
this.Editor.show();
|
||||
},
|
||||
openSystemEditor() {
|
||||
this.CssEditor.openSystemEditor();
|
||||
// this.Editor.openSystemEditor();
|
||||
},
|
||||
recompile() {
|
||||
this.CssEditor.recompile();
|
||||
// this.Editor.recompile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,21 @@ const TEST_ARGS = () => {
|
|||
'paths': {
|
||||
'client': path.resolve(_basePath, 'client', 'dist'),
|
||||
'core': path.resolve(_basePath, 'core', 'dist'),
|
||||
'data': path.resolve(_baseDataPath, 'data')
|
||||
'data': path.resolve(_baseDataPath, 'data'),
|
||||
'editor': path.resolve(_basePath, 'editor', 'dist')
|
||||
}
|
||||
}
|
||||
}
|
||||
const TEST_EDITOR = true;
|
||||
|
||||
import path from 'path';
|
||||
import sass from 'node-sass';
|
||||
import { BrowserWindow as OriginalBrowserWindow, dialog, session } from 'electron';
|
||||
import { BrowserWindow as OriginalBrowserWindow, dialog, session, shell } from 'electron';
|
||||
import deepmerge from 'deepmerge';
|
||||
import ContentSecurityPolicy from 'csp-parse';
|
||||
import keytar from 'keytar';
|
||||
|
||||
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Database } from './modules';
|
||||
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Editor, Database } from './modules';
|
||||
|
||||
const packageJson = require(path.resolve(__dirname, 'package.json'));
|
||||
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
|
||||
|
@ -63,7 +65,8 @@ class Comms {
|
|||
BDIpc.on('bd-sendToDiscord', (event, m) => this.sendToDiscord(m.channel, m.message), true);
|
||||
|
||||
// BDIpc.on('bd-openCssEditor', (event, options) => this.bd.csseditor.openEditor(options), true);
|
||||
BDIpc.on('bd-sendToCssEditor', (event, m) => this.sendToCssEditor(m.channel, m.message), true);
|
||||
// BDIpc.on('bd-sendToCssEditor', (event, m) => this.sendToCssEditor(m.channel, m.message), true);
|
||||
// BDIpc.on('bd-openCssEditor', (event, options) => this.bd.editor.openEditor(options), true);
|
||||
|
||||
BDIpc.on('bd-native-open', (event, options) => {
|
||||
dialog.showOpenDialog(OriginalBrowserWindow.fromWebContents(event.ipcEvent.sender), options, filenames => {
|
||||
|
@ -89,6 +92,48 @@ class Comms {
|
|||
BDIpc.on('bd-keytar-set', (event, { service, account, password }) => keytar.setPassword(service, account, password), true);
|
||||
BDIpc.on('bd-keytar-delete', (event, { service, account }) => keytar.deletePassword(service, account), true);
|
||||
BDIpc.on('bd-keytar-find-credentials', (event, { service }) => keytar.findCredentials(service), true);
|
||||
|
||||
BDIpc.on('bd-readDataFile', async (event, fileName) => {
|
||||
const rf = await FileUtils.readFile(path.resolve(configProxy().getPath('data'), fileName));
|
||||
event.reply(rf);
|
||||
});
|
||||
|
||||
BDIpc.on('bd-explorer', (_, _path) => {
|
||||
if (_path.static) _path = this.bd.config.getPath(_path.static);
|
||||
else if (_path.full) _path = _path.full;
|
||||
else if (_path.sub) _path = path.resolve(this.bd.config.getPath(_path.sub.base), [..._path.sub.subs]);
|
||||
try {
|
||||
shell.openItem(_path);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('bd-getPath', (event, paths) => {
|
||||
event.reply(path.resolve(this.bd.config.getPath(paths[0]), ...paths.splice(1)));
|
||||
});
|
||||
|
||||
BDIpc.on('bd-rmFile', async (event, paths) => {
|
||||
const fullPath = path.resolve(this.bd.config.getPath(paths[0]), ...paths.splice(1));
|
||||
try {
|
||||
await FileUtils.rm(fullPath);
|
||||
event.reply('ok');
|
||||
} catch (err) {
|
||||
event.reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('bd-rnFile', async (event, paths) => {
|
||||
const oldPath = path.resolve(this.bd.config.getPath(paths.oldName[0]), ...paths.oldName.splice(1));
|
||||
const newPath = path.resolve(this.bd.config.getPath(paths.newName[0]), ...paths.newName.splice(1));
|
||||
|
||||
try {
|
||||
await FileUtils.rn(oldPath, newPath);
|
||||
event.reply('ok');
|
||||
} catch (err) {
|
||||
event.reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async send(channel, message) {
|
||||
|
@ -148,7 +193,8 @@ export class BetterDiscord {
|
|||
get comms() { return this._comms ? this._comms : (this._commas = new Comms(this)); }
|
||||
get database() { return this._db ? this._db : (this._db = new Database(this.config.getPath('data'))); }
|
||||
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
|
||||
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
|
||||
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
|
||||
get editor() { return this._editor ? this._editor : (this._editor = new Editor(this, this.config.getPath('editor'))); }
|
||||
|
||||
constructor(args) {
|
||||
if (TESTS) args = TEST_ARGS();
|
||||
|
@ -169,6 +215,7 @@ export class BetterDiscord {
|
|||
|
||||
configProxy = () => this.config;
|
||||
const autoInitComms = this.comms;
|
||||
const autoInitEditor = this.editor;
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -183,9 +230,6 @@ export class BetterDiscord {
|
|||
await this.waitForWindowUtils();
|
||||
await this.ensureDirectories();
|
||||
|
||||
// TODO
|
||||
// this.csseditor = new CSSEditor(this, this.config.getPath('csseditor'));
|
||||
|
||||
this.windowUtils.on('did-finish-load', () => this.injectScripts(true));
|
||||
|
||||
this.windowUtils.on('did-navigate-in-page', (event, url, isMainFrame) => {
|
||||
|
@ -194,15 +238,18 @@ export class BetterDiscord {
|
|||
|
||||
setTimeout(() => {
|
||||
this.injectScripts();
|
||||
if (TEST_EDITOR) this.editor.openEditor({});
|
||||
}, 500);
|
||||
}
|
||||
|
||||
async ensureDirectories() {
|
||||
await FileUtils.ensureDirectory(this.config.getPath('ext'));
|
||||
await FileUtils.ensureDirectory(this.config.getPath('userdata'));
|
||||
await Promise.all([
|
||||
FileUtils.ensureDirectory(this.config.getPath('plugins')),
|
||||
FileUtils.ensureDirectory(this.config.getPath('themes')),
|
||||
FileUtils.ensureDirectory(this.config.getPath('modules'))
|
||||
FileUtils.ensureDirectory(this.config.getPath('modules')),
|
||||
FileUtils.ensureDirectory(this.config.getPath('userfiles'))
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -245,17 +292,23 @@ export class BetterDiscord {
|
|||
* Add extra paths to config
|
||||
*/
|
||||
extraPaths() {
|
||||
const baseDataPath = path.resolve(this.config.getPath('data'), '..');
|
||||
const extPath = path.resolve(baseDataPath, 'ext');
|
||||
const pluginPath = path.resolve(extPath, 'plugins');
|
||||
const themePath = path.resolve(extPath, 'themes');
|
||||
const modulePath = path.resolve(extPath, 'modules');
|
||||
const base = path.resolve(this.config.getPath('data'), '..');
|
||||
const userdata = path.resolve(base, 'userdata');
|
||||
const ext = path.resolve(base, 'ext');
|
||||
const plugins = path.resolve(ext, 'plugins');
|
||||
const themes = path.resolve(ext, 'themes');
|
||||
const modules = path.resolve(ext, 'modules');
|
||||
const userfiles = path.resolve(userdata, 'files');
|
||||
const snippets = path.resolve(userdata, 'snippets.json');
|
||||
|
||||
this.config.addPath('base', baseDataPath);
|
||||
this.config.addPath('ext', extPath);
|
||||
this.config.addPath('plugins', pluginPath);
|
||||
this.config.addPath('themes', themePath);
|
||||
this.config.addPath('modules', modulePath);
|
||||
this.config.addPath('base', base);
|
||||
this.config.addPath('ext', ext);
|
||||
this.config.addPath('plugins', plugins);
|
||||
this.config.addPath('themes', themes);
|
||||
this.config.addPath('modules', modules);
|
||||
this.config.addPath('userdata', userdata);
|
||||
this.config.addPath('userfiles', userfiles);
|
||||
this.config.addPath('snippets', snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
/**
|
||||
* BetterDiscord Editor Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - 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 path from 'path';
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
import Module from './modulebase';
|
||||
import { WindowUtils, FileUtils } from './utils';
|
||||
import BDIpc from './bdipc';
|
||||
import sass from 'node-sass';
|
||||
import chokidar from 'chokidar';
|
||||
|
||||
export default class Editor extends Module {
|
||||
|
||||
constructor(bd, path) {
|
||||
super();
|
||||
this.editorPath = path;
|
||||
this.bd = bd;
|
||||
this.initListeners();
|
||||
this.initWatchers();
|
||||
}
|
||||
|
||||
initListeners() {
|
||||
BDIpc.on('openCssEditor', (event, options) => this.openEditor(options), true);
|
||||
BDIpc.on('editor-open', (event, options) => this.openEditor(options), true);
|
||||
|
||||
BDIpc.on('editor-runScript', async (event, script) => {
|
||||
const result = await this.sendToDiscord('editor-runScript', script);
|
||||
event.reply(result);
|
||||
});
|
||||
|
||||
BDIpc.on('editor-getFiles', async (event) => {
|
||||
try {
|
||||
const files = await FileUtils.listDirectory(this.bd.config.getPath('userfiles'));
|
||||
|
||||
const constructFiles = await Promise.all(files.map(async file => {
|
||||
// const content = await FileUtils.readFile(path.resolve(this.bd.config.getPath('userfiles'), file));
|
||||
return { type: 'file', name: file, saved: true, mode: this.resolveMode(file), content: '', savedContent: '', read: false, changed: false };
|
||||
}));
|
||||
|
||||
const userscssPath = path.resolve(this.bd.config.getPath('data'), 'user.scss');
|
||||
const userscss = await FileUtils.readFile(userscssPath);
|
||||
constructFiles.push({
|
||||
caption: 'userstyle',
|
||||
type: 'file',
|
||||
name: 'user.scss',
|
||||
saved: true,
|
||||
mode: 'scss',
|
||||
content: userscss,
|
||||
savedContent: userscss,
|
||||
hoisted: true,
|
||||
liveUpdate: true,
|
||||
read: true,
|
||||
changed: false
|
||||
});
|
||||
|
||||
event.reply(constructFiles);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
event.reject({ err });
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('editor-getSnippets', async (event) => {
|
||||
try {
|
||||
const snippets = await FileUtils.readJsonFromFile(this.bd.config.getPath('snippets'));
|
||||
event.reply(snippets.map(snippet => {
|
||||
return {
|
||||
type: 'snippet',
|
||||
name: snippet.name,
|
||||
mode: this.resolveMode(snippet.name),
|
||||
content: snippet.content,
|
||||
savedContent: snippet.content,
|
||||
read: true,
|
||||
saved: true
|
||||
}
|
||||
}));
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
event.reply([]);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('editor-saveFile', async (event, file) => {
|
||||
const filePath = (file.hoisted && file.name === 'user.scss') ?
|
||||
path.resolve(this.bd.config.getPath('data'), 'user.scss') :
|
||||
path.resolve(this.bd.config.getPath('userfiles'), file.name);
|
||||
|
||||
try {
|
||||
await FileUtils.writeFile(filePath, file.content);
|
||||
event.reply('ok');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
event.reject({ err });
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('editor-saveSnippet', async (event, snippet) => {
|
||||
try {
|
||||
await FileUtils.writeFile(this.bd.config.getPath('snippets'), JSON.stringify(snippet));
|
||||
event.reply('ok');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
event.reject({ err });
|
||||
}
|
||||
});
|
||||
|
||||
BDIpc.on('editor-injectStyle', async (event, { id, style, mode }) => {
|
||||
if (mode !== 'scss') {
|
||||
await this.sendToDiscord('editor-injectStyle', { id, style });
|
||||
event.reply('ok');
|
||||
return;
|
||||
}
|
||||
|
||||
style = await Promise.all(style.split('\n').map(async(line) => {
|
||||
if (!line.startsWith('@import')) return line;
|
||||
const filename = line.split(' ')[1].replace(/'|"|;/g, '');
|
||||
const filePath = path.resolve(this.bd.config.getPath('userfiles'), filename).replace(/\\/g, '/');
|
||||
|
||||
try {
|
||||
await FileUtils.fileExists(filePath);
|
||||
} catch (err) {
|
||||
`/*${filename}*/`;
|
||||
}
|
||||
|
||||
return `@import '${filePath}';`;
|
||||
}));
|
||||
|
||||
style = style.join('\n');
|
||||
|
||||
sass.render({ data: style }, (err, result) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
event.reply({ err });
|
||||
return;
|
||||
}
|
||||
const { css } = result;
|
||||
(async () => {
|
||||
await this.sendToDiscord('editor-injectStyle', { id, style: css.toString() });
|
||||
event.reply('ok');
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
BDIpc.on('editor-readFile', async (event, file) => {
|
||||
const content = await FileUtils.readFile(path.resolve(this.bd.config.getPath('userfiles'), file.name));
|
||||
event.reply(content);
|
||||
});
|
||||
}
|
||||
|
||||
initWatchers() {
|
||||
this.fileWatcher = chokidar.watch(this.bd.config.getPath('userfiles'));
|
||||
|
||||
this.fileWatcher.on('add', file => {
|
||||
const fileName = path.basename(file);
|
||||
try {
|
||||
this.send('editor-addFile', {
|
||||
type: 'file',
|
||||
name: fileName,
|
||||
saved: true,
|
||||
mode: this.resolveMode(fileName),
|
||||
content: '',
|
||||
savedContent: ''
|
||||
});
|
||||
} catch (err) {}
|
||||
});
|
||||
|
||||
this.fileWatcher.on('unlink', file => {
|
||||
const fileName = path.basename(file);
|
||||
try {
|
||||
this.send('editor-remFile', { name: fileName });
|
||||
} catch (err) {}
|
||||
});
|
||||
|
||||
this.fileWatcher.on('change', file => {
|
||||
this.send('editor-fileChange', { name: path.basename(file) });
|
||||
});
|
||||
}
|
||||
|
||||
resolveMode(fileName) {
|
||||
if (!fileName.includes('.')) return 'text';
|
||||
const ext = fileName.substr(fileName.lastIndexOf('.') + 1);
|
||||
if (this.modes.hasOwnProperty(ext)) return this.modes[ext];
|
||||
return 'text';
|
||||
}
|
||||
|
||||
get modes() {
|
||||
return {
|
||||
'css': 'css',
|
||||
'scss': 'scss',
|
||||
'js': 'javascript',
|
||||
'txt': 'text',
|
||||
'json': 'json'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an editor.
|
||||
* @return {Promise}
|
||||
*/
|
||||
openEditor(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.editor) {
|
||||
if (this.editor.isFocused()) return;
|
||||
|
||||
this.editor.focus();
|
||||
this.editor.flashFrame(true);
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
options = Object.assign({}, this.options, options);
|
||||
|
||||
this.editor = new BrowserWindow(options);
|
||||
this.editor.loadURL('about:blank');
|
||||
this.editor.setSheetOffset(33);
|
||||
this.editorUtils = new WindowUtils({ window: this.editor });
|
||||
|
||||
this.editor.on('close', () => {
|
||||
this.bd.windowUtils.send('bd-save-csseditor-bounds', this.editor.getBounds());
|
||||
this.editor = null;
|
||||
});
|
||||
|
||||
this.editor.once('ready-to-show', () => {
|
||||
this.editor.show();
|
||||
});
|
||||
|
||||
this.editor.webContents.on('did-finish-load', () => {
|
||||
this.editorUtils.injectScript(path.join(this.editorPath, 'editor.js'));
|
||||
resolve(true);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends data to the editor.
|
||||
* @param {String} channel
|
||||
* @param {Any} data
|
||||
*/
|
||||
send(channel, data) {
|
||||
if (!this.editor) throw { message: 'The CSS editor is not open.' };
|
||||
return BDIpc.send(this.editor, channel, data);
|
||||
}
|
||||
|
||||
async sendToDiscord(channel, message) {
|
||||
return this.bd.windowUtils.send(channel, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CSS editor's always on top flag.
|
||||
*/
|
||||
set alwaysOnTop(state) {
|
||||
if (!this.editor) return;
|
||||
this.editor.setAlwaysOnTop(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default options to pass to BrowserWindow.
|
||||
*/
|
||||
get options() {
|
||||
return {
|
||||
width: 800,
|
||||
height: 600,
|
||||
show: false,
|
||||
frame: false
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -2,4 +2,5 @@ export { default as BDIpc } from './bdipc';
|
|||
export { Utils, FileUtils, WindowUtils } from './utils';
|
||||
export { default as Config } from './config';
|
||||
export { default as CSSEditor } from './csseditor';
|
||||
export { default as Editor } from './editor';
|
||||
export { default as Database } from './database';
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// TODO Use common
|
||||
|
||||
import fs from 'fs';
|
||||
import rimraf from 'rimraf';
|
||||
|
||||
import Module from './modulebase';
|
||||
import BDIpc from './bdipc';
|
||||
|
@ -99,6 +100,15 @@ export class FileUtils {
|
|||
}
|
||||
}
|
||||
|
||||
static async writeFile(path, data, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.writeFile(path, data, options, err => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static async listDirectory(path) {
|
||||
try {
|
||||
await this.directoryExists(path);
|
||||
|
@ -155,6 +165,27 @@ export class FileUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async rm(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rimraf(path, err => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
reject(err);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static async rn(oldPath, newPath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.rename(oldPath, newPath, err => {
|
||||
if (err) return reject(err);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowUtils extends Module {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "bdeditorwindow",
|
||||
"description": "BetterDiscord editor window",
|
||||
"author": "JsSucks",
|
||||
"version": "0.4.0",
|
||||
"homepage": "https://betterdiscord.net",
|
||||
"license": "MIT",
|
||||
"main": "dist/csseditor.js",
|
||||
"contributors": [
|
||||
"Jiiks",
|
||||
"Pohky"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/JsSucks/BetterDiscordApp.git"
|
||||
},
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"build": "webpack --progress --colors",
|
||||
"watch": "webpack --progress --colors --watch",
|
||||
"release": "webpack --progress --colors --config=webpack.production.config.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="titlebar">
|
||||
<div class="draggable"></div>
|
||||
<div class="icon">
|
||||
<div class="inner"></div>
|
||||
</div>
|
||||
<div class="title">Content Editor</div>
|
||||
<div class="flex-spacer"></div>
|
||||
<div class="controls">
|
||||
<button :class="{active: alwaysOnTop}" ref="aot" title="Toggle always on top" @click="toggleaot">P</button>
|
||||
<button title="Close CSS Editor" @click="close">X</button>
|
||||
</div>
|
||||
</div>
|
||||
<BDEdit :files="files"
|
||||
:parentLoading="loading"
|
||||
:snippets="snippets"
|
||||
:updateContent="updateContent"
|
||||
:runScript="runScript"
|
||||
:newFile="newFile"
|
||||
:saveFile="saveFile"
|
||||
:newSnippet="newSnippet"
|
||||
:saveSnippet="saveSnippet"
|
||||
:readFile="readFile"
|
||||
:readSnippet="readSnippet"
|
||||
:injectStyle="injectStyle"
|
||||
:toggleLiveUpdate="toggleLiveUpdate"
|
||||
:ctxAction="ctxAction"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ClientIPC } from 'common';
|
||||
import { remote } from 'electron';
|
||||
|
||||
import { BDEdit } from 'bdedit';
|
||||
|
||||
ace.acequire = ace.require;
|
||||
|
||||
const modes = {
|
||||
'css': 'css',
|
||||
'scss': 'scss',
|
||||
'js': 'javascript',
|
||||
'txt': 'text',
|
||||
'json': 'json'
|
||||
};
|
||||
|
||||
function resolveMode(fileName) {
|
||||
if (!fileName.includes('.')) return 'text';
|
||||
const ext = fileName.substr(fileName.lastIndexOf('.') + 1);
|
||||
if (modes.hasOwnProperty(ext)) return modes[ext];
|
||||
return 'text';
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
files: [],
|
||||
snippets: [],
|
||||
loading: true,
|
||||
alwaysOnTop: false,
|
||||
error: undefined,
|
||||
lastSaved: undefined
|
||||
}
|
||||
},
|
||||
components: { BDEdit },
|
||||
created() {
|
||||
ClientIPC.on('bd-editor-addFile', (_, file) => {
|
||||
if (this.files.find(f => f.name === file.name)) return;
|
||||
this.addFile(file);
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-editor-remFile', (_, file) => {
|
||||
this.files = this.files.filter(f => f.name !== file.name);
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-editor-addSnippet', (_, snippet) => {
|
||||
if (this.snippets.find(s => s.name === snippet.name)) return;
|
||||
this.addSnippet(snippet);
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-editor-remSnippet', (_, snippet) => {
|
||||
this.snippets = this.snippets.filter(s => s.name !== snippet.name);
|
||||
});
|
||||
|
||||
ClientIPC.on('bd-editor-fileChange', (_, file) => {
|
||||
if (this.lastSaved && this.lastSaved.name === file.name) { // If we saved in our editor then don't trigger
|
||||
this.lastSaved = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const f = this.files.find(f => f.name === file.name);
|
||||
if (f) f.changed = true;
|
||||
});
|
||||
},
|
||||
async mounted() {
|
||||
this.files = await ClientIPC.send('bd-editor-getFiles');
|
||||
this.snippets = await ClientIPC.send('bd-editor-getSnippets');
|
||||
this.loading = false;
|
||||
},
|
||||
methods: {
|
||||
addFile(file) {
|
||||
this.files.push(file);
|
||||
},
|
||||
|
||||
addSnippet(snippet) { this.snippets.push(file) },
|
||||
|
||||
updateContent(item, content) {
|
||||
item.content = content;
|
||||
item.saved = item.content === item.savedContent;
|
||||
|
||||
if (this.liveUpdateTimeout) clearTimeout(this.liveUpdateTimeout);
|
||||
if (item.liveUpdateEnabled) {
|
||||
this.liveUpdateTimeout = setTimeout(() => {
|
||||
this.injectStyle(item);
|
||||
}, 5000);
|
||||
}
|
||||
},
|
||||
|
||||
async runScript(script) {
|
||||
return ClientIPC.send('editor-runScript', script);
|
||||
},
|
||||
|
||||
newFile(fileName) {
|
||||
const prefix = fileName;
|
||||
const mode = resolveMode(fileName);
|
||||
|
||||
let newName = prefix;
|
||||
let iter = 0;
|
||||
|
||||
while (this.files.find(file => file.name === newName)) {
|
||||
newName = `${prefix.split('.')[0]}_${iter}.${prefix.split('.')[1]}`;
|
||||
iter++;
|
||||
}
|
||||
|
||||
const newItem = { type: 'file', name: newName, content: '', mode, saved: false, read: true };
|
||||
this.files.push(newItem);
|
||||
return newItem;
|
||||
},
|
||||
|
||||
newSnippet(snippetName) {
|
||||
const prefix = snippetName;
|
||||
const mode = resolveMode(snippetName);
|
||||
|
||||
let newName = prefix;
|
||||
let iter = 0;
|
||||
|
||||
while (this.snippets.find(snippet => snippet.name === newName)) {
|
||||
newName = `${prefix}_${iter}`;
|
||||
iter++;
|
||||
}
|
||||
|
||||
const newItem = { type: 'snippet', name: newName, content: '', savedContent: '', mode, saved: false, read: true };
|
||||
this.snippets.push(newItem);
|
||||
return newItem;
|
||||
},
|
||||
|
||||
async saveFile(file) {
|
||||
try {
|
||||
this.lastSaved = file;
|
||||
const result = await ClientIPC.send('bd-editor-saveFile', file);
|
||||
file.savedContent = file.content;
|
||||
file.saved = true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
|
||||
async saveSnippet(snippet) {
|
||||
snippet.saved = true;
|
||||
snippet.savedContent = snippet.content;
|
||||
const result = await ClientIPC.send('bd-editor-saveSnippet', this.snippets.map(snippet => {
|
||||
return {
|
||||
name: snippet.name,
|
||||
content: snippet.savedContent
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
async readFile(file) {
|
||||
const content = await ClientIPC.send('editor-readFile', file);
|
||||
file.read = true;
|
||||
file.changed = false;
|
||||
file.content = file.savedContent = content;
|
||||
return content;
|
||||
},
|
||||
|
||||
async readSnippet(snippet) {
|
||||
const content = await ClientIPC.send('editor-readSnippet', snippet);
|
||||
snippet.read = true;
|
||||
return content;
|
||||
},
|
||||
|
||||
async injectStyle(item) {
|
||||
const style = item.content.length <= 0 ? ' ' : item.content;
|
||||
const result = await ClientIPC.send('bd-editor-injectStyle', { id: item.name.split('.')[0], style, mode: item.mode });
|
||||
return result;
|
||||
},
|
||||
|
||||
async ctxAction(action, item) {
|
||||
if (action === 'reveal') {
|
||||
ClientIPC.send('explorer', { 'static': 'userfiles' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'copy') {
|
||||
remote.clipboard.writeText(item.content);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'copyPath') {
|
||||
const fullPath = await ClientIPC.send('getPath', ['userfiles', item.name]);
|
||||
remote.clipboard.writeText(fullPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'rename') { // TODO select correct file after
|
||||
this.loading = true;
|
||||
const { oldName, newName } = item;
|
||||
|
||||
try {
|
||||
await ClientIPC.send('rnFile', { oldName: ['userfiles', oldName], newName: ['userfiles', newName] });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'delete') {
|
||||
this.loading = true;
|
||||
try {
|
||||
await ClientIPC.send('rmFile', ['userfiles', item.name]);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
toggleLiveUpdate(item) {
|
||||
item.liveUpdateEnabled = !item.liveUpdateEnabled;
|
||||
return item;
|
||||
},
|
||||
|
||||
toggleaot() {
|
||||
this.alwaysOnTop = !this.alwaysOnTop;
|
||||
remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop);
|
||||
},
|
||||
|
||||
close() {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,22 @@
|
|||
// const styles = require('./styles/index.scss');
|
||||
|
||||
import Vue from 'vue';
|
||||
|
||||
import Editor from './Editor.vue';
|
||||
import styles from './styles/index.scss';
|
||||
|
||||
const mount = document.createElement('div');
|
||||
mount.classList.add('container');
|
||||
document.body.appendChild(mount);
|
||||
|
||||
const vue = new Vue({
|
||||
el: mount,
|
||||
components: { Editor },
|
||||
template: '<Editor/>'
|
||||
});
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.id = 'bd-main';
|
||||
style.type = 'text/css';
|
||||
style.appendChild(document.createTextNode(styles));
|
||||
document.head.appendChild(style);
|
|
@ -0,0 +1,20 @@
|
|||
@import './vars.scss';
|
||||
@import './titlebar.scss';
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
max-height: 100%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #2c383e;
|
||||
min-width: 700px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
.titlebar {
|
||||
display: flex;
|
||||
height: 25px;
|
||||
padding: 4px 5px;
|
||||
background: #292b2f;
|
||||
border-bottom: 1px solid hsla(218,5%,47%,.3);
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
|
||||
.icon {
|
||||
width: 31px;
|
||||
height: 25px;
|
||||
|
||||
.inner {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
background-image: $bdicon;
|
||||
background-size: 22px 22px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #bac9d2;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
line-height: 25px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.flex-spacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin: 0 0 0 2px;
|
||||
font-size: 0;
|
||||
|
||||
button {
|
||||
-webkit-app-region: no-drag;
|
||||
outline: none !important;
|
||||
border-radius: 3px;
|
||||
width: 25px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: #36393f;
|
||||
color: #bac9d2;
|
||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
transition: background-color .2s ease, color .2s ease;
|
||||
cursor: default;
|
||||
border: 0;
|
||||
height: 25px;
|
||||
z-index: 900062;
|
||||
padding: 0;
|
||||
margin: 0 0 0 4px;
|
||||
|
||||
&:hover {
|
||||
background: $bdGreen;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $bdGreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.draggable {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 63px;
|
||||
position: absolute;
|
||||
height: 33px;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
$logoSmallGw: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkltYWdlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7ZGlzcGxheTpub25lO30uc3Qxe2Rpc3BsYXk6aW5saW5lO2ZpbGw6IzAyMDAzNTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9LnN0MntmaWxsOiMzRUNDOUU7fS5zdDN7ZmlsbDojRkZGRkZGO308L3N0eWxlPjxnIGlkPSJMYXllcl8yIiBjbGFzcz0ic3QwIj48cmVjdCB4PSItNjQiIHk9Ii0zMiIgY2xhc3M9InN0MSIgd2lkdGg9IjYxOCIgaGVpZ2h0PSI1NzIiLz48L2c+PGcgaWQ9IkxheWVyXzEiIHhtbG5zOnZlY3Rvcm5hdG9yPSJodHRwOi8vdmVjdG9ybmF0b3IuaW8iPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik03MCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3YyMzMuNkM0Mi43LDM5Ny43LDEzNy45LDQ5MywyNTYsNDkzYzI5LjcsMCw1OC02LjEsODMuNi0xN1YzNDEuNWMtMTksMjUuNi00OS4zLDQyLjItODMuNiw0Mi4yYy01Ny42LDAtMTA0LjEtNDYuNS0xMDQuMS0xMDQuMVY0Ni4xYzAtMTMuNy0xMy43LTI3LjMtMjcuMy0yNy4zSDcweiIvPjxwYXRoIGNsYXNzPSJzdDMiIGQ9Ik0zODcuNCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3Y0Ny4zQzMyOS4zLDc2LjIsMjkzLjksNjYuMywyNTYsNjYuM2MtMjkuOCwwLTU3LjksNi4zLTgzLjYsMTcuM3YxMzQuMmMxOS0yNS42LDQ5LjMtNDIuMiw4My42LTQyLjJjNTcuNiwwLDEwNC4xLDQ2LjUsMTA0LjEsMTA0LjF2MTg2LjJjNjUuMi0zNi40LDEwOS4yLTEwNiwxMDkuMi0xODYuMlY0Ni4xYzAtMTguOC0xMy43LTI3LjMtMjcuMy0yNy4zSDM4Ny40eiIvPjwvZz48L3N2Zz4=);
|
||||
$bdicon: $logoSmallGw;
|
||||
$bdGreen: #3ecc9c;
|
|
@ -0,0 +1,39 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const vueLoader = {
|
||||
test: /\.(vue)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'vue-loader'
|
||||
};
|
||||
|
||||
const scssLoader = {
|
||||
test: /\.(css|scss)$/,
|
||||
loader: ['css-loader', 'sass-loader']
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'editor.js'
|
||||
},
|
||||
module: {
|
||||
loaders: [vueLoader, scssLoader]
|
||||
},
|
||||
externals: {
|
||||
electron: 'window.require("electron")',
|
||||
fs: 'window.require("fs")',
|
||||
util: 'window.require("util")',
|
||||
process: 'require("process")'
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
||||
},
|
||||
modules: [
|
||||
path.resolve('..', 'node_modules'),
|
||||
path.resolve('..', 'common', 'modules')
|
||||
]
|
||||
}
|
||||
};
|
|
@ -15,6 +15,11 @@
|
|||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg="
|
||||
},
|
||||
"ace-builds": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.3.tgz",
|
||||
"integrity": "sha512-T+e4DQRQR8ReNPOUryXWdXRX1NBTb9rB1y42IhnH4mmFe0NIIpAQVu8BQ9tgU2K3EGaPFZeG7E87OOjaXDP8PQ=="
|
||||
},
|
||||
"acorn": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
|
||||
|
@ -1581,6 +1586,12 @@
|
|||
"tweetnacl": "0.14.5"
|
||||
}
|
||||
},
|
||||
"bdedit": {
|
||||
"version": "github:JsSucks/bdedit#95cea7f8d55cf97a9e7dff9d0bf82c7af7c38312",
|
||||
"requires": {
|
||||
"ace-builds": "1.4.3"
|
||||
}
|
||||
},
|
||||
"beeper": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"private": false,
|
||||
"dependencies": {
|
||||
"asar": "^0.14.6",
|
||||
"bdedit": "github:JsSucks/bdedit",
|
||||
"csp-parse": "github:macropodhq/csp-parse",
|
||||
"deepmerge": "^2.2.1",
|
||||
"fs-extra": "^7.0.0",
|
||||
|
@ -82,7 +83,9 @@
|
|||
"watch_core": "npm run watch --prefix core",
|
||||
"build_csseditor": "npm run build --prefix csseditor",
|
||||
"watch_csseditor": "npm run watch --prefix csseditor",
|
||||
"lint": "eslint -f unix client/src core/src csseditor/src common && npm run sasslint",
|
||||
"build_editor": "npm run build --prefix editor",
|
||||
"watch_editor": "npm run watch --prefix editor",
|
||||
"lint": "eslint -f unix client/src core/src editor/src common && npm run sasslint",
|
||||
"lint_fix": "eslint -f unix client/src core/src csseditor/src common --fix",
|
||||
"sasslint": "sass-lint client/src/styles/**/*.scss -v",
|
||||
"test": "npm run build && npm run lint",
|
||||
|
|
Loading…
Reference in New Issue