diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx
index ed8cb87d5..d6502e985 100644
--- a/client/homebrew/editor/editor.jsx
+++ b/client/homebrew/editor/editor.jsx
@@ -10,6 +10,8 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
const SnippetBar = require('./snippetbar/snippetbar.jsx');
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
+const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME';
+
const SNIPPETBAR_HEIGHT = 25;
const DEFAULT_STYLE_TEXT = dedent`
/*=======--- Example CSS styling ---=======*/
@@ -34,12 +36,14 @@ const Editor = createClass({
onMetaChange : ()=>{},
reportError : ()=>{},
- renderer : 'legacy'
+ editorTheme : 'default',
+ renderer : 'legacy'
};
},
getInitialState : function() {
return {
- view : 'text' //'text', 'style', 'meta'
+ editorTheme : this.props.editorTheme,
+ view : 'text' //'text', 'style', 'meta'
};
},
@@ -51,6 +55,13 @@ const Editor = createClass({
this.updateEditorSize();
this.highlightCustomMarkdown();
window.addEventListener('resize', this.updateEditorSize);
+
+ const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
+ if(editorTheme) {
+ this.setState({
+ editorTheme : editorTheme
+ });
+ }
},
componentWillUnmount : function() {
@@ -255,6 +266,13 @@ const Editor = createClass({
this.refs.codeEditor?.updateSize();
},
+ updateEditorTheme : function(newTheme){
+ window.localStorage.setItem(EDITOR_THEME_KEY, newTheme);
+ this.setState({
+ editorTheme : newTheme
+ });
+ },
+
//Called by CodeEditor after document switch, so Snippetbar can refresh UndoHistory
rerenderParent : function (){
this.forceUpdate();
@@ -269,6 +287,7 @@ const Editor = createClass({
view={this.state.view}
value={this.props.brew.text}
onChange={this.props.onTextChange}
+ editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} />
>;
}
@@ -281,6 +300,7 @@ const Editor = createClass({
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
onChange={this.props.onStyleChange}
enableFolding={false}
+ editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} />
>;
}
@@ -324,6 +344,8 @@ const Editor = createClass({
undo={this.undo}
redo={this.redo}
historySize={this.historySize()}
+ currentEditorTheme={this.state.editorTheme}
+ updateEditorTheme={this.updateEditorTheme}
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
{this.renderEditor()}
diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less
index 86e523a13..db88b5b0f 100644
--- a/client/homebrew/editor/editor.less
+++ b/client/homebrew/editor/editor.less
@@ -1,4 +1,4 @@
-
+@import 'themes/codeMirror/customEditorStyles.less';
.editor{
position : relative;
width : 100%;
diff --git a/client/homebrew/editor/snippetbar/snippetbar.jsx b/client/homebrew/editor/snippetbar/snippetbar.jsx
index fee1a5780..246d534a9 100644
--- a/client/homebrew/editor/snippetbar/snippetbar.jsx
+++ b/client/homebrew/editor/snippetbar/snippetbar.jsx
@@ -1,3 +1,4 @@
+/*eslint max-lines: ["warn", {"max": 250, "skipBlankLines": true, "skipComments": true}]*/
require('./snippetbar.less');
const React = require('react');
const createClass = require('create-react-class');
@@ -15,6 +16,8 @@ ThemeSnippets['V3_5eDMG'] = require('themes/V3/5eDMG/snippets.js');
ThemeSnippets['V3_Journal'] = require('themes/V3/Journal/snippets.js');
ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js');
+const EditorThemes = require('build/homebrew/codeMirror/editorThemes.json');
+
const execute = function(val, props){
if(_.isFunction(val)) return val(props);
return val;
@@ -24,24 +27,26 @@ const Snippetbar = createClass({
displayName : 'SnippetBar',
getDefaultProps : function() {
return {
- brew : {},
- view : 'text',
- onViewChange : ()=>{},
- onInject : ()=>{},
- onToggle : ()=>{},
- showEditButtons : true,
- renderer : 'legacy',
- undo : ()=>{},
- redo : ()=>{},
- historySize : ()=>{},
- cursorPos : {}
+ brew : {},
+ view : 'text',
+ onViewChange : ()=>{},
+ onInject : ()=>{},
+ onToggle : ()=>{},
+ showEditButtons : true,
+ renderer : 'legacy',
+ undo : ()=>{},
+ redo : ()=>{},
+ historySize : ()=>{},
+ updateEditorTheme : ()=>{},
+ cursorPos : {}
};
},
getInitialState : function() {
return {
- renderer : this.props.renderer,
- snippets : []
+ renderer : this.props.renderer,
+ themeSelector : false,
+ snippets : []
};
},
@@ -95,6 +100,31 @@ const Snippetbar = createClass({
this.props.onInject(injectedText);
},
+ toggleThemeSelector : function(){
+ this.setState({
+ themeSelector : !this.state.themeSelector
+ });
+ },
+
+ changeTheme : function(e){
+ if(e.target.value == this.props.currentEditorTheme) return;
+ this.props.updateEditorTheme(e.target.value);
+
+ this.setState({
+ showThemeSelector : false,
+ });
+ },
+
+ renderThemeSelector : function(){
+ return
+
+
;
+ },
+
renderSnippetGroups : function(){
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
@@ -124,6 +154,12 @@ const Snippetbar = createClass({
+
+
+
+ {this.state.themeSelector && this.renderThemeSelector()}
+
this.props.onViewChange('text')}>
@@ -196,5 +232,4 @@ const SnippetGroup = createClass({
;
},
-
});
diff --git a/client/homebrew/editor/snippetbar/snippetbar.less b/client/homebrew/editor/snippetbar/snippetbar.less
index cb24da105..ed2dcebce 100644
--- a/client/homebrew/editor/snippetbar/snippetbar.less
+++ b/client/homebrew/editor/snippetbar/snippetbar.less
@@ -46,6 +46,15 @@
color : black;
}
}
+ &.editorTheme{
+ .tooltipLeft('Editor Themes');
+ font-size : 0.75em;
+ color : black;
+ &.active{
+ color : white;
+ background-color: black;
+ }
+ }
&.divider {
background: linear-gradient(#000, #000) no-repeat center/1px 100%;
width: 5px;
@@ -54,6 +63,15 @@
}
}
}
+ .themeSelector{
+ position: absolute;
+ left: -65px;
+ top: 30px;
+ z-index: 999;
+ width: 170px;
+ background-color: black;
+ border-radius: 5px;
+ }
}
.snippetBarButton{
height : @menuHeight;
diff --git a/scripts/buildHomebrew.js b/scripts/buildHomebrew.js
index 3bf0065d0..e78759168 100644
--- a/scripts/buildHomebrew.js
+++ b/scripts/buildHomebrew.js
@@ -99,6 +99,24 @@ fs.emptyDirSync('./build');
await fs.copy('./themes/assets', './build/assets');
await fs.copy('./client/icons', './build/icons');
+ //v==---------------------------MOVE CM EDITOR THEMES -----------------------------==v//
+
+ editorThemeFiles = fs.readdirSync('./node_modules/codemirror/theme');
+
+ const editorThemeFile = './themes/codeMirror/editorThemes.json';
+ if(fs.existsSync(editorThemeFile)) fs.rmSync(editorThemeFile);
+ const stream = fs.createWriteStream(editorThemeFile, { flags: 'a' });
+ stream.write('[\n"default"');
+
+ for (themeFile of editorThemeFiles) {
+ stream.write(`,\n"${themeFile.slice(0, -4)}"`);
+ }
+ stream.write('\n]\n');
+ stream.end();
+
+ await fs.copy('./node_modules/codemirror/theme', './build/homebrew/cm-themes');
+ await fs.copy('./themes/codeMirror', './build/homebrew/codeMirror');
+
//v==----------------------------- BUNDLE PACKAGES --------------------------------==v//
const bundles = await pack('./client/homebrew/homebrew.jsx', {
diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx
index 2b5685e49..e0a2220b4 100644
--- a/shared/naturalcrit/codeEditor/codeEditor.jsx
+++ b/shared/naturalcrit/codeEditor/codeEditor.jsx
@@ -49,7 +49,8 @@ const CodeEditor = createClass({
value : '',
wrap : true,
onChange : ()=>{},
- enableFolding : true
+ enableFolding : true,
+ editorTheme : 'default'
};
},
@@ -91,6 +92,10 @@ const CodeEditor = createClass({
} else {
this.codeMirror.setOption('foldOptions', false);
}
+
+ if(prevProps.editorTheme !== this.props.editorTheme){
+ this.codeMirror.setOption('theme', this.props.editorTheme);
+ }
},
buildEditor : function() {
@@ -159,6 +164,7 @@ const CodeEditor = createClass({
autoCloseTags : true,
styleActiveLine : true,
showTrailingSpace : false,
+ theme : this.props.editorTheme
// specialChars : / /,
// specialCharPlaceholder : function(char) {
// const el = document.createElement('span');
@@ -406,7 +412,10 @@ const CodeEditor = createClass({
//----------------------//
render : function(){
- return ;
+ return <>
+
+
+ >;
}
});
diff --git a/themes/codeMirror/customEditorStyles.less b/themes/codeMirror/customEditorStyles.less
new file mode 100644
index 000000000..3318e1305
--- /dev/null
+++ b/themes/codeMirror/customEditorStyles.less
@@ -0,0 +1,88 @@
+.editor .codeEditor .CodeMirror {
+ // Themes with dark backgrounds
+ &.cm-s-3024-night,
+ &.cm-s-abbott,
+ &.cm-s-abcdef,
+ &.cm-s-ambiance,
+ &.cm-s-ayu-dark,
+ &.cm-s-ayu-mirage,
+ &.cm-s-base16-dark,
+ &.cm-s-bespin,
+ &.cm-s-blackboard,
+ &.cm-s-cobalt,
+ &.cm-s-colorforth,
+ &.cm-s-darcula,
+ &.cm-s-dracula,
+ &.cm-s-duotone-dark,
+ &.cm-s-erlang-dark,
+ &.cm-s-gruvbox-dark,
+ &.cm-s-hopscotch,
+ &.cm-s-icecoder,
+ &.cm-s-isotope,
+ &.cm-s-lesser-dark,
+ &.cm-s-liquibyte,
+ &.cm-s-lucario,
+ &.cm-s-material,
+ &.cm-s-material-darker,
+ &.cm-s-material-ocean,
+ &.cm-s-material-palenight,
+ &.cm-s-mbo,
+ &.cm-s-midnight,
+ &.cm-s-monokai,
+ &.cm-s-moxer,
+ &.cm-s-night,
+ &.cm-s-nord,
+ &.cm-s-oceanic-next,
+ &.cm-s-panda-syntax,
+ &.cm-s-paraiso-dark,
+ &.cm-s-pastel-on-dark,
+ &.cm-s-railscasts,
+ &.cm-s-rubyblue,
+ &.cm-s-seti,
+ &.cm-s-shadowfox,
+ &.cm-s-the-matrix,
+ &.cm-s-tomorrow-night-bright,
+ &.cm-s-tomorrow-night-eighties,
+ &.cm-s-twilight,
+ &.cm-s-vibrant-ink,
+ &.cm-s-xq-dark,
+ &.cm-s-yonce,
+ &.cm-s-zenburn
+ {
+ .CodeMirror-code {
+ .block:not(.cm-comment) {
+ color: magenta;
+ }
+ .columnSplit {
+ color: black;
+ background-color: rgba(35,153,153,0.5);
+ }
+ .pageLine {
+ background-color: rgba(255,255,255,0.75);
+ & ~ pre.CodeMirror-line {
+ color: black;
+ }
+ }
+ }
+ }
+ // Themes with light backgrounds
+ &.cm-s-default,
+ &.cm-s-3024-day,
+ &.cm-s-ambiance-mobile,
+ &.cm-s-base16-light,
+ &.cm-s-duotone-light,
+ &.cm-s-eclipse,
+ &.cm-s-elegant,
+ &.cm-s-juejin,
+ &.cm-s-neat,
+ &.cm-s-neo,
+ &.cm-s-paraiso-lightm
+ &.cm-s-solarized,
+ &.cm-s-ssms,
+ &.cm-s-ttcn,
+ &.cm-s-xq-light,
+ &.cm-s-yeti {
+ // Future styling for themes with light backgrounds
+ --dummyVar: 'currently unused';
+ }
+}
\ No newline at end of file
diff --git a/themes/codeMirror/editorThemes.json b/themes/codeMirror/editorThemes.json
new file mode 100644
index 000000000..a4dd74470
--- /dev/null
+++ b/themes/codeMirror/editorThemes.json
@@ -0,0 +1,68 @@
+[
+"default",
+"3024-day",
+"3024-night",
+"abbott",
+"abcdef",
+"ambiance-mobile",
+"ambiance",
+"ayu-dark",
+"ayu-mirage",
+"base16-dark",
+"base16-light",
+"bespin",
+"blackboard",
+"cobalt",
+"colorforth",
+"darcula",
+"dracula",
+"duotone-dark",
+"duotone-light",
+"eclipse",
+"elegant",
+"erlang-dark",
+"gruvbox-dark",
+"hopscotch",
+"icecoder",
+"idea",
+"isotope",
+"juejin",
+"lesser-dark",
+"liquibyte",
+"lucario",
+"material-darker",
+"material-ocean",
+"material-palenight",
+"material",
+"mbo",
+"mdn-like",
+"midnight",
+"monokai",
+"moxer",
+"neat",
+"neo",
+"night",
+"nord",
+"oceanic-next",
+"panda-syntax",
+"paraiso-dark",
+"paraiso-light",
+"pastel-on-dark",
+"railscasts",
+"rubyblue",
+"seti",
+"shadowfox",
+"solarized",
+"ssms",
+"the-matrix",
+"tomorrow-night-bright",
+"tomorrow-night-eighties",
+"ttcn",
+"twilight",
+"vibrant-ink",
+"xq-dark",
+"xq-light",
+"yeti",
+"yonce",
+"zenburn"
+]