more customcss stuff
This commit is contained in:
parent
8ee16509a8
commit
8b907bf8fe
|
@ -34,7 +34,8 @@
|
|||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-uses-vars": "error",
|
||||
"react/prop-types": 0,
|
||||
"react/jsx-no-target-blank": "error"
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-key": 0
|
||||
},
|
||||
"globals": {
|
||||
"webpackJsonp": false,
|
||||
|
|
32
css/main.css
32
css/main.css
|
@ -85,6 +85,14 @@
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.checkbox-item .checkbox-label {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -606,7 +614,7 @@ color: #f6f6f7;
|
|||
.bd-detached-css-editor #bd-customcss-attach-controls button {
|
||||
margin: 0;
|
||||
width: 100px;
|
||||
background: #31332b;
|
||||
background: #2F3129;
|
||||
color: #FFF;
|
||||
height: 26px;
|
||||
font-weight: 600;
|
||||
|
@ -616,7 +624,7 @@ color: #f6f6f7;
|
|||
|
||||
.standardSidebarView-3F1I7i #bd-customcss-attach-controls button:hover,
|
||||
.bd-detached-css-editor #bd-customcss-attach-controls button:hover {
|
||||
background: #3b3e44;
|
||||
background: rgb(59,61,51);
|
||||
}
|
||||
|
||||
.contentRegion-3nDuYy #bd-customcss-attach-controls,
|
||||
|
@ -768,6 +776,17 @@ color: #f6f6f7;
|
|||
#bd-customcss-attach-controls button {
|
||||
margin: 0;
|
||||
width: 100px;
|
||||
border-radius: 0px;
|
||||
border-left: 2px solid rgb(63, 65, 70);
|
||||
}
|
||||
|
||||
#bd-customcss-attach-controls button:first-of-type {
|
||||
border-radius: 3px 0px 0px 3px;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
#bd-customcss-attach-controls button:last-of-type {
|
||||
border-radius: 0px 3px 3px 0px;
|
||||
}
|
||||
|
||||
#bd-customcss-detach-container #bd-customcss-detach-controls-buttons button {
|
||||
|
@ -779,8 +798,13 @@ color: #f6f6f7;
|
|||
font-size: 19px;
|
||||
}
|
||||
|
||||
#bd-customcss-attach-controls .small-notice {
|
||||
font-size: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* Ace Editor Settings */
|
||||
body > div:not([class]):last-of-type {
|
||||
#ace_settingsmenu_container {
|
||||
background: rgba(0,0,0, 0.7)!important;
|
||||
}
|
||||
|
||||
|
@ -816,7 +840,7 @@ body .ace_closeButton:active {
|
|||
}
|
||||
|
||||
#bd-customcss-attach-controls .help-text .inline {
|
||||
background: #31332B;
|
||||
background: #2F3129;
|
||||
padding: .2em;
|
||||
margin: -.2em 0;
|
||||
border-radius: 3px;
|
||||
|
|
File diff suppressed because one or more lines are too long
80
js/main.js
80
js/main.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,8 @@
|
|||
"watch": "webpack --progress --colors --watch",
|
||||
"build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"minify": "gulp minify-css",
|
||||
"minify": "npm run build-prod && npm run minify-css",
|
||||
"minify-css": "gulp minify-css",
|
||||
"watch-css": "gulp watch-css"
|
||||
},
|
||||
"repository": {
|
||||
|
|
|
@ -1,20 +1,66 @@
|
|||
import Builtin from "../structs/builtin";
|
||||
import {Settings} from "modules";
|
||||
import {Settings, DataStore, React, Events} from "modules";
|
||||
import CSSEditor from "../ui/customcss/editor";
|
||||
|
||||
const electron = require("electron");
|
||||
|
||||
export default new class CustomCSS extends Builtin {
|
||||
get name() {return "Custom CSS";}
|
||||
get category() {return "customcss";}
|
||||
get id() {return "customcss";}
|
||||
get startDetached() {return Settings.get(this.collection, this.category, "startDetached");}
|
||||
get nativeOpen() {return Settings.get(this.collection, this.category, "nativeOpen");}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.css = "";
|
||||
}
|
||||
|
||||
enabled() {
|
||||
Settings.registerPanel(this.id, this.name, {
|
||||
element: CSSEditor,
|
||||
order: 2
|
||||
order: 2,
|
||||
element: () => React.createElement(CSSEditor, {
|
||||
css: this.css,
|
||||
save: this.saveCSS.bind(this),
|
||||
update: this.insertCSS.bind(this),
|
||||
openNative: this.openNative.bind(this)
|
||||
}),
|
||||
onClick: (thisObject) => {
|
||||
if (this.nativeOpen) this.openNative();
|
||||
else if (this.startDetached) this.openDetached();
|
||||
else thisObject._reactInternalFiber.child.memoizedProps.children.props.onSetSection(this.name);
|
||||
}
|
||||
});
|
||||
this.loadCSS();
|
||||
this.insertCSS();
|
||||
}
|
||||
|
||||
disabled() {
|
||||
Settings.removePanel(this.id);
|
||||
}
|
||||
|
||||
loadCSS() {
|
||||
this.css = DataStore.loadCustomCSS();
|
||||
}
|
||||
|
||||
insertCSS(newCss) {
|
||||
if (typeof(newCss) === "undefined") newCss = this.css;
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(newCss).detach().appendTo(document.head);
|
||||
}
|
||||
|
||||
saveCSS(newCss) {
|
||||
if (typeof(newCss) !== "undefined") this.css = newCss;
|
||||
DataStore.saveCustomCSS(this.css);
|
||||
}
|
||||
|
||||
openNative() {
|
||||
electron.shell.openExternal(`file://${DataStore.customCSS}`);
|
||||
}
|
||||
|
||||
openDetached() {
|
||||
this.log("Should open detached");
|
||||
}
|
||||
};
|
|
@ -21,12 +21,12 @@ export default new class WindowPrefs extends Builtin {
|
|||
}
|
||||
|
||||
enabled() {
|
||||
this.setWindowPreference("transparency", true);
|
||||
this.setWindowPreference("transparent", true);
|
||||
this.setWindowPreference("backgroundColor", null);
|
||||
}
|
||||
|
||||
disabled() {
|
||||
this.setWindowPreference("transparency", false);
|
||||
this.setWindowPreference("transparent", false);
|
||||
this.setWindowPreference("backgroundColor", "#2f3136");
|
||||
}
|
||||
|
||||
|
|
|
@ -196,14 +196,16 @@ export default [
|
|||
id: "startDetached",
|
||||
name: "Start Detached",
|
||||
note: "Clicking the Custom CSS tab opens the editor in a separate window",
|
||||
value: false
|
||||
value: false,
|
||||
disableWith: "nativeOpen"
|
||||
},
|
||||
{
|
||||
type: "switch",
|
||||
id: "nativeOpen",
|
||||
name: "Open in Native Editor",
|
||||
note: "Clicking the Custom CSS tab opens your custom css in your native editor",
|
||||
value: false
|
||||
value: false,
|
||||
disableWith: "startDetached"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ export default new class DataStore {
|
|||
if (!fs.existsSync(this.baseFolder)) fs.mkdirSync(this.baseFolder);
|
||||
if (!fs.existsSync(this.dataFolder)) fs.mkdirSync(this.dataFolder);
|
||||
if (!fs.existsSync(this.BDFile)) fs.writeFileSync(this.BDFile, JSON.stringify(this.data.misc, null, 4));
|
||||
if (!fs.existsSync(this.customCSS)) fs.writeFileSync(this.customCSS, "");
|
||||
const dataFiles = fs.readdirSync(this.dataFolder).filter(f => !fs.statSync(path.resolve(this.dataFolder, f)).isDirectory() && f.endsWith(".json"));
|
||||
for (const file of dataFiles) {
|
||||
this.data[file.split(".")[0]] = __non_webpack_require__(path.resolve(this.dataFolder, file));
|
||||
|
@ -42,6 +43,7 @@ export default new class DataStore {
|
|||
// this.setBDData("settings", settings);
|
||||
}
|
||||
|
||||
get customCSS() {return this._customCSS || (this._customCSS = path.resolve(this.dataFolder, "custom.css"));}
|
||||
get baseFolder() {return this._baseFolder || (this._baseFolder = path.resolve(Config.dataPath, "data"));}
|
||||
get dataFolder() {return this._dataFolder || (this._dataFolder = path.resolve(this.baseFolder, `${releaseChannel}`));}
|
||||
get BDFile() {return this._BDFile || (this._BDFile = path.resolve(Config.dataPath, "data", `${releaseChannel}.json`));}
|
||||
|
@ -82,6 +84,14 @@ export default new class DataStore {
|
|||
fs.writeFileSync(path.resolve(this.dataFolder, `${key}.json`), JSON.stringify(value, null, 4));
|
||||
}
|
||||
|
||||
loadCustomCSS() {
|
||||
return fs.readFileSync(this.customCSS).toString();
|
||||
}
|
||||
|
||||
saveCustomCSS(css) {
|
||||
return fs.writeFileSync(this.customCSS, css);
|
||||
}
|
||||
|
||||
getPluginData(pluginName, key) {
|
||||
if (this.pluginData[pluginName] !== undefined) return this.pluginData[pluginName][key] || undefined;
|
||||
if (!fs.existsSync(this.getPluginFile(pluginName))) return undefined;
|
||||
|
|
|
@ -5,7 +5,6 @@ import WebpackModules, {DiscordModules} from "./webpackmodules";
|
|||
|
||||
import {SettingsPanel as SettingsRenderer} from "ui";
|
||||
import Utilities from "./utilities";
|
||||
import {Toasts} from "ui";
|
||||
|
||||
export default new class SettingsManager {
|
||||
|
||||
|
@ -44,8 +43,8 @@ export default new class SettingsManager {
|
|||
if (this.panels.find(p => p.id == id)) return Utilities.err("Settings", "Already have a panel with id " + id);
|
||||
const {element, onClick, order = 1} = options;
|
||||
const section = {id, order, label: name, section: name};
|
||||
if (onClick) section.onClick = onClick;
|
||||
else section.element = element instanceof DiscordModules.React.Component ? () => DiscordModules.React.createElement(element, {}) : typeof(element) == "function" ? element : () => element;
|
||||
if (onClick) section.clickListener = onClick;
|
||||
if (element) section.element = element instanceof DiscordModules.React.Component ? () => DiscordModules.React.createElement(element, {}) : typeof(element) == "function" ? element : () => element;
|
||||
this.panels.push(section);
|
||||
}
|
||||
|
||||
|
@ -84,22 +83,30 @@ export default new class SettingsManager {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (setting.disableWith) {
|
||||
const path = this.getPath(setting.disableWith.split("."), collection.id, category.id);
|
||||
if (setting.hasOwnProperty("disabled")) continue;
|
||||
Object.defineProperty(setting, "disabled", {
|
||||
get: () => {
|
||||
return this.state[path.collection][path.category][path.setting];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collection.enableWith) {
|
||||
const path = this.getPath(collection.enableWith.split("."));
|
||||
Object.defineProperty(collection, "disabled", {
|
||||
get: () => {
|
||||
return !this.state[path.collection][path.category][path.setting];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async patchSections() {
|
||||
Utilities.monkeyPatch(WebpackModules.getByDisplayName("FluxContainer(GuildSettings)").prototype, "render", {after: (data) => {
|
||||
data.thisObject._reactInternalFiber.return.return.return.return.return.return.memoizedProps.id = "guild-settings";
|
||||
}});
|
||||
const UserSettings = await this.getUserSettings();
|
||||
Utilities.monkeyPatch(UserSettings.prototype, "render", {after: (data) => {
|
||||
data.thisObject._reactInternalFiber.return.return.return.return.return.return.return.memoizedProps.id = "user-settings";
|
||||
}});
|
||||
Utilities.monkeyPatch(UserSettings.prototype, "generateSections", {after: (data) => {
|
||||
let location = data.returnValue.findIndex(s => s.section.toLowerCase() == "linux") + 1;
|
||||
const insert = (section) => {
|
||||
|
@ -116,8 +123,10 @@ export default new class SettingsManager {
|
|||
element: () => SettingsRenderer.buildSettingsPanel(collection.name, collection.settings, this.state[collection.id], this.onSettingChange.bind(this, collection.id), collection.button ? collection.button : null)
|
||||
});
|
||||
}
|
||||
for (const panel of this.panels.sort((a,b) => a.order > b.order)) insert(panel);
|
||||
insert({section: "BBD Test", label: "Test Tab", onClick: function() {Toasts.success("This can just be a click listener!", {forceShow: true});}});
|
||||
for (const panel of this.panels.sort((a,b) => a.order > b.order)) {
|
||||
if (panel.clickListener) panel.onClick = (event) => panel.clickListener(data.thisObject, event, data.returnValue);
|
||||
insert(panel);
|
||||
}
|
||||
insert({section: "CUSTOM", element: () => SettingsRenderer.attribution});
|
||||
}});
|
||||
this.forceUpdate();
|
||||
|
@ -166,7 +175,7 @@ export default new class SettingsManager {
|
|||
Events.dispatch("setting-updated", collection, category, id, value);
|
||||
const after = this.collections.length + this.panels.length;
|
||||
this.saveSettings();
|
||||
if (before != after) this.forceUpdate();
|
||||
if (before != after) setTimeout(this.forceUpdate.bind(this), 50);
|
||||
}
|
||||
|
||||
getSetting(collection, category, id) {
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class Checkbox extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.state = {
|
||||
checked: this.props.checked || false
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return React.createElement(
|
||||
"li",
|
||||
null,
|
||||
React.createElement(
|
||||
"div",
|
||||
{className: "checkbox checkbox-3kaeSU da-checkbox checkbox-3EVISJ da-checkbox", onClick: this.onClick},
|
||||
React.createElement(
|
||||
"div",
|
||||
{className: "checkbox-inner checkboxInner-3yjcPe da-checkboxInner"},
|
||||
React.createElement("input", {className: "checkboxElement-1qV33p da-checkboxElement", checked: this.state.checked, onChange: () => {}, type: "checkbox"}),
|
||||
React.createElement("span", null)
|
||||
),
|
||||
React.createElement(
|
||||
"span",
|
||||
null,
|
||||
this.props.text
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.props.onChange(this.props.id, !this.state.checked);
|
||||
this.setState({
|
||||
checked: !this.state.checked
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class Checkbox extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.state = {checked: this.props.checked || false};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className="checkbox-item">
|
||||
<div className="checkbox-label label-JWQiNe da-label">{this.props.text}</div>
|
||||
<div className="checkbox-wrapper checkbox-3kaeSU da-checkbox checkbox-3EVISJ da-checkbox" onClick={this.onClick}>
|
||||
<div className="checkbox-inner checkboxInner-3yjcPe da-checkboxInner">
|
||||
<input className="checkbox checkboxElement-1qV33p da-checkboxElement" checked={this.state.checked} type="checkbox" />
|
||||
<span></span>
|
||||
</div>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.props.onChange(!this.state.checked);
|
||||
this.setState({checked: !this.state.checked});
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
import {SettingsCookie} from "data";
|
||||
import {BDV2, DataStore, Core, DiscordModules} from "modules";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
|
||||
export default class CssEditorDetached extends DiscordModules.React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.updateCss = this.updateCss.bind(this);
|
||||
this.saveCss = this.saveCss.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$("#app-mount").addClass("bd-detached-editor");
|
||||
BDV2.editorDetached = true;
|
||||
// this.updateLineCount();
|
||||
this.editor = ace.edit("bd-customcss-editor-detached");
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.session.setMode("ace/mode/css");
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.setFontSize(14);
|
||||
this.editor.on("change", () => {
|
||||
if (!SettingsCookie["bda-css-0"]) return;
|
||||
this.saveCss();
|
||||
this.updateCss();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$("#app-mount").removeClass("bd-detached-editor");
|
||||
BDV2.editorDetached = false;
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
||||
updateLineCount() {
|
||||
const lineCount = this.refs.editor.value.split("\n").length;
|
||||
if (lineCount == this.props.lines) return;
|
||||
this.refs.lines.textContent = Array.from(new Array(lineCount), (_, i) => i + 1).join(".\n") + ".";
|
||||
this.props.lines = lineCount;
|
||||
}
|
||||
|
||||
get options() {
|
||||
return {
|
||||
lineNumbers: true,
|
||||
mode: "css",
|
||||
indentUnit: 4,
|
||||
theme: "material",
|
||||
scrollbarStyle: "simple"
|
||||
};
|
||||
}
|
||||
|
||||
get css() {
|
||||
const _ccss = DataStore.getBDData("bdcustomcss");
|
||||
let ccss = "";
|
||||
if (_ccss && _ccss !== "") {
|
||||
ccss = atob(_ccss);
|
||||
}
|
||||
return ccss;
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-customcss-detach-container");
|
||||
if (!_root.length) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.detachedRoot;
|
||||
}
|
||||
return _root[0];
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".app, .app-2rEoOp").length) return false;
|
||||
$("<div/>", {
|
||||
id: "bd-customcss-detach-container"
|
||||
}).insertAfter($(".app, .app-2rEoOp"));
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const self = this;
|
||||
return DiscordModules.React.createElement(
|
||||
"div",
|
||||
{className: "bd-detached-css-editor", id: "bd-customcss-detach-editor"},
|
||||
DiscordModules.React.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-innerpane"},
|
||||
DiscordModules.React.createElement("div", {className: "editor-wrapper"},
|
||||
DiscordModules.React.createElement("div", {id: "bd-customcss-editor-detached", className: "editor", ref: "editor"}, self.css)
|
||||
),
|
||||
DiscordModules.React.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-attach-controls"},
|
||||
DiscordModules.React.createElement(
|
||||
"ul",
|
||||
{className: "checkbox-group"},
|
||||
DiscordModules.React.createElement(Checkbox, {id: "live-update", text: "Live Update", onChange: self.onChange, checked: SettingsCookie["bda-css-0"]})
|
||||
),
|
||||
DiscordModules.React.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-detach-controls-button"},
|
||||
DiscordModules.React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "3px 0 0 3px", borderRight: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("update");
|
||||
}},
|
||||
"Update"
|
||||
),
|
||||
DiscordModules.React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0", borderLeft: "1px solid #2d2d2d", borderRight: "1px solid #2d2d2d"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("save");
|
||||
}},
|
||||
"Save"
|
||||
),
|
||||
DiscordModules.React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0 3px 3px 0", borderLeft: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("attach");
|
||||
}},
|
||||
"Attach"
|
||||
),
|
||||
DiscordModules.React.createElement(
|
||||
"span",
|
||||
{style: {fontSize: "10px", marginLeft: "5px"}},
|
||||
"Unsaved changes are lost on attach"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange(id, checked) {
|
||||
switch (id) {
|
||||
case "live-update":
|
||||
SettingsCookie["bda-css-0"] = checked;
|
||||
Core.saveSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onClick(id) {
|
||||
const self = this;
|
||||
switch (id) {
|
||||
case "attach":
|
||||
if ($("#editor-detached").length) self.props.attach();
|
||||
DiscordModules.ReactDOM.unmountComponentAtNode(self.root);
|
||||
self.root.remove();
|
||||
break;
|
||||
case "update":
|
||||
self.updateCss();
|
||||
break;
|
||||
case "save":
|
||||
self.saveCss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
|
||||
}
|
||||
}
|
|
@ -1,222 +0,0 @@
|
|||
import {BDV2, DataStore, React, ReactDOM, Settings} from "modules";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
import SettingsTitle from "../settings/title";
|
||||
|
||||
export default class CssEditor extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props.lines = 0;
|
||||
this.state = {
|
||||
detached: this.props.detached || BDV2.editorDetached
|
||||
};
|
||||
// this.attach = this.attach.bind(this);
|
||||
// this.detachedEditor = React.createElement(EditorDetached, {attach: this.attach});
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.updateCss = this.updateCss.bind(this);
|
||||
this.saveCss = this.saveCss.bind(this);
|
||||
this.detach = this.detach.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.updateLineCount();
|
||||
this.editor = ace.edit("bd-customcss-editor");
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.session.setMode("ace/mode/css");
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.setFontSize(14);
|
||||
this.editor.on("change", () => {
|
||||
if (!Settings.get("settings", "customcss", "liveUpdate")) return;
|
||||
this.saveCss();
|
||||
this.updateCss();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevState.detached && !this.state.detached) {
|
||||
ReactDOM.unmountComponentAtNode(this.detachedRoot);
|
||||
}
|
||||
}
|
||||
|
||||
codeMirror() {
|
||||
}
|
||||
|
||||
get options() {
|
||||
return {
|
||||
lineNumbers: true,
|
||||
mode: "css",
|
||||
indentUnit: 4,
|
||||
theme: "material",
|
||||
scrollbarStyle: "simple"
|
||||
};
|
||||
}
|
||||
|
||||
get css() {
|
||||
const _ccss = DataStore.getBDData("bdcustomcss");
|
||||
let ccss = "";
|
||||
if (_ccss && _ccss !== "") {
|
||||
ccss = atob(_ccss);
|
||||
}
|
||||
return ccss;
|
||||
}
|
||||
|
||||
updateLineCount() {
|
||||
const lineCount = this.refs.editor.value.split("\n").length;
|
||||
if (lineCount == this.props.lines) return;
|
||||
this.refs.lines.textContent = Array.from(new Array(lineCount), (_, i) => i + 1).join(".\n") + ".";
|
||||
this.props.lines = lineCount;
|
||||
}
|
||||
|
||||
render() {
|
||||
const self = this;
|
||||
return React.createElement(
|
||||
"div",
|
||||
{className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default", style: {padding: "60px 40px 0px"}},
|
||||
// detached && React.createElement(
|
||||
// "div",
|
||||
// {id: "editor-detached"},
|
||||
// React.createElement(SettingsTitle, {text: "Custom CSS Editor"}),
|
||||
// React.createElement(
|
||||
// "h3",
|
||||
// null,
|
||||
// "Editor Detached"
|
||||
// ),
|
||||
// React.createElement(
|
||||
// "button",
|
||||
// {className: "btn btn-primary", onClick: () => {
|
||||
// self.attach();
|
||||
// }},
|
||||
// "Attach"
|
||||
// )
|
||||
// ),
|
||||
/*!detached && */React.createElement(
|
||||
"div",
|
||||
null,
|
||||
React.createElement(SettingsTitle, {text: "Custom CSS Editor"}),
|
||||
React.createElement("div", {className: "editor-wrapper"},
|
||||
React.createElement("div", {id: "bd-customcss-editor", className: "editor", ref: "editor"}, self.css)
|
||||
),
|
||||
React.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-attach-controls"},
|
||||
React.createElement(
|
||||
"ul",
|
||||
{className: "checkbox-group"},
|
||||
React.createElement(Checkbox, {id: "live-update", text: "Live Update", onChange: this.onChange, checked: Settings.get("settings", "customcss", "liveUpdate")})
|
||||
),
|
||||
React.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-detach-controls-button"},
|
||||
React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "3px 0 0 3px", borderRight: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("update");
|
||||
}},
|
||||
"Update"
|
||||
),
|
||||
React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0", borderLeft: "1px solid #2d2d2d", borderRight: "1px solid #2d2d2d"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("save");
|
||||
}},
|
||||
"Save"
|
||||
),
|
||||
React.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0 3px 3px 0", borderLeft: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("detach");
|
||||
}},
|
||||
"Detach"
|
||||
),
|
||||
React.createElement(
|
||||
"span",
|
||||
{style: {fontSize: "10px", marginLeft: "5px"}},
|
||||
"Unsaved changes are lost on detach"
|
||||
),
|
||||
React.createElement("div", {className: "help-text"},
|
||||
"Press ",
|
||||
React.createElement("code", {className: "inline"}, "ctrl"),
|
||||
"+",
|
||||
React.createElement("span", {className: "inline"}, ","),
|
||||
" with the editor focused to access the editor's settings."
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onClick(arg) {
|
||||
switch (arg) {
|
||||
case "update":
|
||||
this.updateCss();
|
||||
break;
|
||||
case "save":
|
||||
this.saveCss();
|
||||
break;
|
||||
case "detach":
|
||||
this.detach();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onChange(id, checked) {
|
||||
switch (id) {
|
||||
case "live-update":
|
||||
Settings.set("settings", "customcss", "liveUpdate", checked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
|
||||
}
|
||||
|
||||
detach() {
|
||||
return console.log("DETACH");
|
||||
// this.setState({
|
||||
// detached: true
|
||||
// });
|
||||
// const droot = this.detachedRoot;
|
||||
// if (!droot) {
|
||||
// console.log("FAILED TO INJECT ROOT: .app");
|
||||
// return;
|
||||
// }
|
||||
// ReactDOM.render(this.detachedEditor, droot);
|
||||
}
|
||||
|
||||
// get detachedRoot() {
|
||||
// const _root = $("#bd-customcss-detach-container");
|
||||
// if (!_root.length) {
|
||||
// if (!this.injectDetachedRoot()) return null;
|
||||
// return this.detachedRoot;
|
||||
// }
|
||||
// return _root[0];
|
||||
// }
|
||||
|
||||
// injectDetachedRoot() {
|
||||
// if (!$(".app, .app-2rEoOp").length) return false;
|
||||
// $("<div/>", {
|
||||
// id: "bd-customcss-detach-container"
|
||||
// }).insertAfter($(".app, .app-2rEoOp"));
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// attach() {
|
||||
// this.setState({
|
||||
// detached: false
|
||||
// });
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
import {React, Settings} from "modules";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
import SettingsTitle from "../settings/title";
|
||||
|
||||
export default class CssEditor extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.toggleLiveUpdate = this.toggleLiveUpdate.bind(this);
|
||||
this.updateCss = this.updateCss.bind(this);
|
||||
this.saveCss = this.saveCss.bind(this);
|
||||
this.detach = this.detach.bind(this);
|
||||
this.openNative = this.openNative.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.editor = ace.edit("bd-customcss-editor");
|
||||
|
||||
// Add id to the ace menu container
|
||||
const originalShow = this.editor.keyBinding.$defaultHandler.commands.showSettingsMenu.exec;
|
||||
this.editor.keyBinding.$defaultHandler.commands.showSettingsMenu.exec = function() {
|
||||
originalShow.apply(this, arguments);
|
||||
const observer = new MutationObserver(mutations => {
|
||||
for (const mutation of mutations) {
|
||||
if (!mutation.addedNodes.length || !(mutation.addedNodes[0] instanceof Element)) continue;
|
||||
const node = mutation.addedNodes[0];
|
||||
if (node.parentElement !== document.body || !node.querySelector("#ace_settingsmenu")) continue;
|
||||
node.id = "ace_settingsmenu_container";
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
observer.observe(document.body, {childList: true});
|
||||
};
|
||||
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.session.setMode("ace/mode/css");
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.setFontSize(14);
|
||||
this.editor.on("change", () => {
|
||||
if (!Settings.get("settings", "customcss", "liveUpdate")) return;
|
||||
this.saveCss();
|
||||
this.updateCss();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return [
|
||||
<SettingsTitle text="Custom CSS Editor" />,
|
||||
<div className="editor-wrapper">
|
||||
<div id="bd-customcss-editor" className="editor">{this.props.css}</div>
|
||||
</div>,
|
||||
<div id="bd-customcss-attach-controls">
|
||||
<div className="checkbox-group">
|
||||
<Checkbox text="Live Update" onChange={this.toggleLiveUpdate} checked={Settings.get("settings", "customcss", "liveUpdate")} />
|
||||
</div>
|
||||
<div id="bd-customcss-detach-controls-button">
|
||||
<button className="btn btn-primary" onClick={this.updateCss}>Update</button>
|
||||
<button className="btn btn-primary" onClick={this.saveCss}>Save</button>
|
||||
<button className="btn btn-primary" onClick={this.openNative}>Open Natively</button>
|
||||
<button className="btn btn-primary" onClick={this.detach}>Detach</button>
|
||||
<span className="small-notice">Unsaved changes are lost on detach</span>
|
||||
<div className="help-text">
|
||||
Press <code className="inline">ctrl</code>+<code className="inline">,</code> with the editor focused to access the editor's settings.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
];
|
||||
}
|
||||
|
||||
toggleLiveUpdate(checked) {
|
||||
Settings.set("settings", "customcss", "liveUpdate", checked);
|
||||
}
|
||||
|
||||
updateCss() {
|
||||
const newCss = this.editor.session.getValue();
|
||||
if (this.props.update) this.props.update(newCss);
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
const newCss = this.editor.session.getValue();
|
||||
if (this.props.save) this.props.save(newCss);
|
||||
}
|
||||
|
||||
detach() {
|
||||
if (this.props.openDetached) this.props.openDetached();
|
||||
}
|
||||
|
||||
openNative() {
|
||||
if (this.props.openNative) this.props.openNative();
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class BDLogo extends React.Component {
|
||||
render() {
|
||||
return React.createElement("svg",
|
||||
{height: "100%", width: this.props.size || "16px", className: "bd-logo " + this.props.className, style: {fillRule: "evenodd", clipRule: "evenodd", strokeLinecap: "round", strokeLinejoin: "round"}, viewBox: "0 0 2000 2000"},
|
||||
React.createElement("metadata", null),
|
||||
React.createElement("defs", null,
|
||||
React.createElement("filter", {id: "shadow1"}, React.createElement("feDropShadow", {"dx": "20", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(0,0,0,0.35)"})),
|
||||
React.createElement("filter", {id: "shadow2"}, React.createElement("feDropShadow", {"dx": "15", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(255,255,255,0.15)"})),
|
||||
React.createElement("filter", {id: "shadow3"}, React.createElement("feDropShadow", {"dx": "10", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(0,0,0,0.35)"}))
|
||||
),
|
||||
React.createElement("g", null,
|
||||
React.createElement("path", {style: {filter: "url(#shadow3)"}, d: "M1195.44+135.442L1195.44+135.442L997.6+136.442C1024.2+149.742+1170.34+163.542+1193.64+179.742C1264.34+228.842+1319.74+291.242+1358.24+365.042C1398.14+441.642+1419.74+530.642+1422.54+629.642L1422.54+630.842L1422.54+632.042C1422.54+773.142+1422.54+1228.14+1422.54+1369.14L1422.54+1370.34L1422.54+1371.54C1419.84+1470.54+1398.24+1559.54+1358.24+1636.14C1319.74+1709.94+1264.44+1772.34+1193.64+1821.44C1171.04+1837.14+1025.7+1850.54+1000+1863.54L1193.54+1864.54C1539.74+1866.44+1864.54+1693.34+1864.54+1296.64L1864.54+716.942C1866.44+312.442+1541.64+135.442+1195.44+135.442Z", fill: "#171717", opacity: "1"}),
|
||||
React.createElement("path", {style: {filter: "url(#shadow2)"}, d: "M1695.54+631.442C1685.84+278.042+1409.34+135.442+1052.94+135.442L361.74+136.442L803.74+490.442L1060.74+490.442C1335.24+490.442+1335.24+835.342+1060.74+835.342L1060.74+1164.84C1150.22+1164.84+1210.53+1201.48+1241.68+1250.87C1306.07+1353+1245.76+1509.64+1060.74+1509.64L361.74+1863.54L1052.94+1864.54C1409.24+1864.54+1685.74+1721.94+1695.54+1368.54C1695.54+1205.94+1651.04+1084.44+1572.64+999.942C1651.04+915.542+1695.54+794.042+1695.54+631.442Z", fill: "#3E82E5", opacity: "1"}),
|
||||
React.createElement("path", {style: {filter: "url(#shadow1)"}, d: "M1469.25+631.442C1459.55+278.042+1183.05+135.442+826.65+135.442L135.45+135.442L135.45+1004C135.45+1004+135.427+1255.21+355.626+1255.21C575.825+1255.21+575.848+1004+575.848+1004L577.45+490.442L834.45+490.442C1108.95+490.442+1108.95+835.342+834.45+835.342L664.65+835.342L664.65+1164.84L834.45+1164.84C923.932+1164.84+984.244+1201.48+1015.39+1250.87C1079.78+1353+1019.47+1509.64+834.45+1509.64L135.45+1509.64L135.45+1864.54L826.65+1864.54C1182.95+1864.54+1459.45+1721.94+1469.25+1368.54C1469.25+1205.94+1424.75+1084.44+1346.35+999.942C1424.75+915.542+1469.25+794.042+1469.25+631.442Z", fill: "#FFFFFF", opacity: "1"})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class BDLogo extends React.Component {
|
||||
render() {
|
||||
return <svg className={"bd-logo " + this.props.className} height="100%" width={this.props.size || "16px"} viewBox="0 0 2000 2000" style={{fillRule: "evenodd", clipRule: "evenodd", strokeLinecap: "round", strokeLinejoin: "round"}}>
|
||||
<metadata />
|
||||
<defs>
|
||||
<filter id="shadow1"><feDropShadow dx="20" dy="0" stdDeviation="20" floodColor="rgba(0,0,0,0.35)" /></filter>
|
||||
<filter id="shadow2"><feDropShadow dx="15" dy="0" stdDeviation="20" floodColor="rgba(255,255,255,0.15)" /></filter>
|
||||
<filter id="shadow3"><feDropShadow dx="10" dy="0" stdDeviation="20" floodColor="rgba(0,0,0,0.35)" /></filter>
|
||||
</defs>
|
||||
<g>
|
||||
<path style={{filter: "url(#shadow3)"}} fill="#171717" opacity="1" d="M1195.44+135.442L1195.44+135.442L997.6+136.442C1024.2+149.742+1170.34+163.542+1193.64+179.742C1264.34+228.842+1319.74+291.242+1358.24+365.042C1398.14+441.642+1419.74+530.642+1422.54+629.642L1422.54+630.842L1422.54+632.042C1422.54+773.142+1422.54+1228.14+1422.54+1369.14L1422.54+1370.34L1422.54+1371.54C1419.84+1470.54+1398.24+1559.54+1358.24+1636.14C1319.74+1709.94+1264.44+1772.34+1193.64+1821.44C1171.04+1837.14+1025.7+1850.54+1000+1863.54L1193.54+1864.54C1539.74+1866.44+1864.54+1693.34+1864.54+1296.64L1864.54+716.942C1866.44+312.442+1541.64+135.442+1195.44+135.442Z" />
|
||||
<path style={{filter: "url(#shadow2)"}} fill="#3E82E5" opacity="1" d="M1695.54+631.442C1685.84+278.042+1409.34+135.442+1052.94+135.442L361.74+136.442L803.74+490.442L1060.74+490.442C1335.24+490.442+1335.24+835.342+1060.74+835.342L1060.74+1164.84C1150.22+1164.84+1210.53+1201.48+1241.68+1250.87C1306.07+1353+1245.76+1509.64+1060.74+1509.64L361.74+1863.54L1052.94+1864.54C1409.24+1864.54+1685.74+1721.94+1695.54+1368.54C1695.54+1205.94+1651.04+1084.44+1572.64+999.942C1651.04+915.542+1695.54+794.042+1695.54+631.442Z" />
|
||||
<path style={{filter: "url(#shadow1)"}} fill="#FFFFFF" opacity="1" d="M1469.25+631.442C1459.55+278.042+1183.05+135.442+826.65+135.442L135.45+135.442L135.45+1004C135.45+1004+135.427+1255.21+355.626+1255.21C575.825+1255.21+575.848+1004+575.848+1004L577.45+490.442L834.45+490.442C1108.95+490.442+1108.95+835.342+834.45+835.342L664.65+835.342L664.65+1164.84L834.45+1164.84C923.932+1164.84+984.244+1201.48+1015.39+1250.87C1079.78+1353+1019.47+1509.64+834.45+1509.64L135.45+1509.64L135.45+1864.54L826.65+1864.54C1182.95+1864.54+1459.45+1721.94+1469.25+1368.54C1469.25+1205.94+1424.75+1084.44+1346.35+999.942C1424.75+915.542+1469.25+794.042+1469.25+631.442Z" />
|
||||
</g>
|
||||
</svg>;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class XSvg extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return React.createElement(
|
||||
"svg",
|
||||
{xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 12 12", style: {width: "18px", height: "18px"}},
|
||||
React.createElement(
|
||||
"g",
|
||||
{className: "background", fill: "none", fillRule: "evenodd"},
|
||||
React.createElement("path", {d: "M0 0h12v12H0"}),
|
||||
React.createElement("path", {className: "fill", fill: "#dcddde", d: "M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6"})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class CloseButton extends React.Component {
|
||||
render() {
|
||||
return <svg viewBox="0 0 12 12" style={{width: "18px", height: "18px"}}>
|
||||
<g className="background" fill="none" fillRule="evenodd">
|
||||
<path d="M0 0h12v12H0" />
|
||||
<path className="fill" fill="#dcddde" d="M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6" />
|
||||
</g>
|
||||
</svg>;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class ReloadIcon extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return React.createElement("svg", {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "#dcddde",
|
||||
className: "bd-reload " + this.props.className,
|
||||
onClick: this.props.onClick,
|
||||
style: {width: this.props.size || "24px", height: this.props.size || "24px"}
|
||||
},
|
||||
React.createElement("path", {d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"}),
|
||||
React.createElement("path", {fill: "none", d: "M0 0h24v24H0z"})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import {React} from "modules";
|
||||
|
||||
export default class ReloadIcon extends React.Component {
|
||||
render() {
|
||||
const size = this.props.size || "24px";
|
||||
return <svg className={"bd-reload " + this.props.className} onClick={this.props.onClick} fill="#dcddde" viewBox="0 0 24 24" style={{width: size, height: size}}>
|
||||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" />
|
||||
<path fill="none" d="M0 0h24v24H0z" />
|
||||
</svg>;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue