mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-07 03:22:38 +00:00
Merge pull request #2768 from G-Ambatte/addEditorThemes-#362
Add editor themes
This commit is contained in:
@@ -10,6 +10,8 @@ const CodeEditor = require('naturalcrit/codeEditor/codeEditor.jsx');
|
|||||||
const SnippetBar = require('./snippetbar/snippetbar.jsx');
|
const SnippetBar = require('./snippetbar/snippetbar.jsx');
|
||||||
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
|
const MetadataEditor = require('./metadataEditor/metadataEditor.jsx');
|
||||||
|
|
||||||
|
const EDITOR_THEME_KEY = 'HOMEBREWERY-EDITOR-THEME';
|
||||||
|
|
||||||
const SNIPPETBAR_HEIGHT = 25;
|
const SNIPPETBAR_HEIGHT = 25;
|
||||||
const DEFAULT_STYLE_TEXT = dedent`
|
const DEFAULT_STYLE_TEXT = dedent`
|
||||||
/*=======--- Example CSS styling ---=======*/
|
/*=======--- Example CSS styling ---=======*/
|
||||||
@@ -34,12 +36,14 @@ const Editor = createClass({
|
|||||||
onMetaChange : ()=>{},
|
onMetaChange : ()=>{},
|
||||||
reportError : ()=>{},
|
reportError : ()=>{},
|
||||||
|
|
||||||
renderer : 'legacy'
|
editorTheme : 'default',
|
||||||
|
renderer : 'legacy'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getInitialState : function() {
|
getInitialState : function() {
|
||||||
return {
|
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.updateEditorSize();
|
||||||
this.highlightCustomMarkdown();
|
this.highlightCustomMarkdown();
|
||||||
window.addEventListener('resize', this.updateEditorSize);
|
window.addEventListener('resize', this.updateEditorSize);
|
||||||
|
|
||||||
|
const editorTheme = window.localStorage.getItem(EDITOR_THEME_KEY);
|
||||||
|
if(editorTheme) {
|
||||||
|
this.setState({
|
||||||
|
editorTheme : editorTheme
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount : function() {
|
componentWillUnmount : function() {
|
||||||
@@ -255,6 +266,13 @@ const Editor = createClass({
|
|||||||
this.refs.codeEditor?.updateSize();
|
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
|
//Called by CodeEditor after document switch, so Snippetbar can refresh UndoHistory
|
||||||
rerenderParent : function (){
|
rerenderParent : function (){
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
@@ -269,6 +287,7 @@ const Editor = createClass({
|
|||||||
view={this.state.view}
|
view={this.state.view}
|
||||||
value={this.props.brew.text}
|
value={this.props.brew.text}
|
||||||
onChange={this.props.onTextChange}
|
onChange={this.props.onTextChange}
|
||||||
|
editorTheme={this.state.editorTheme}
|
||||||
rerenderParent={this.rerenderParent} />
|
rerenderParent={this.rerenderParent} />
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
@@ -281,6 +300,7 @@ const Editor = createClass({
|
|||||||
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
value={this.props.brew.style ?? DEFAULT_STYLE_TEXT}
|
||||||
onChange={this.props.onStyleChange}
|
onChange={this.props.onStyleChange}
|
||||||
enableFolding={false}
|
enableFolding={false}
|
||||||
|
editorTheme={this.state.editorTheme}
|
||||||
rerenderParent={this.rerenderParent} />
|
rerenderParent={this.rerenderParent} />
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
@@ -324,6 +344,8 @@ const Editor = createClass({
|
|||||||
undo={this.undo}
|
undo={this.undo}
|
||||||
redo={this.redo}
|
redo={this.redo}
|
||||||
historySize={this.historySize()}
|
historySize={this.historySize()}
|
||||||
|
currentEditorTheme={this.state.editorTheme}
|
||||||
|
updateEditorTheme={this.updateEditorTheme}
|
||||||
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
|
cursorPos={this.refs.codeEditor?.getCursorPosition() || {}} />
|
||||||
|
|
||||||
{this.renderEditor()}
|
{this.renderEditor()}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
@import 'themes/codeMirror/customEditorStyles.less';
|
||||||
.editor{
|
.editor{
|
||||||
position : relative;
|
position : relative;
|
||||||
width : 100%;
|
width : 100%;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/*eslint max-lines: ["warn", {"max": 250, "skipBlankLines": true, "skipComments": true}]*/
|
||||||
require('./snippetbar.less');
|
require('./snippetbar.less');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const createClass = require('create-react-class');
|
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_Journal'] = require('themes/V3/Journal/snippets.js');
|
||||||
ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js');
|
ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js');
|
||||||
|
|
||||||
|
const EditorThemes = require('build/homebrew/codeMirror/editorThemes.json');
|
||||||
|
|
||||||
const execute = function(val, props){
|
const execute = function(val, props){
|
||||||
if(_.isFunction(val)) return val(props);
|
if(_.isFunction(val)) return val(props);
|
||||||
return val;
|
return val;
|
||||||
@@ -24,24 +27,26 @@ const Snippetbar = createClass({
|
|||||||
displayName : 'SnippetBar',
|
displayName : 'SnippetBar',
|
||||||
getDefaultProps : function() {
|
getDefaultProps : function() {
|
||||||
return {
|
return {
|
||||||
brew : {},
|
brew : {},
|
||||||
view : 'text',
|
view : 'text',
|
||||||
onViewChange : ()=>{},
|
onViewChange : ()=>{},
|
||||||
onInject : ()=>{},
|
onInject : ()=>{},
|
||||||
onToggle : ()=>{},
|
onToggle : ()=>{},
|
||||||
showEditButtons : true,
|
showEditButtons : true,
|
||||||
renderer : 'legacy',
|
renderer : 'legacy',
|
||||||
undo : ()=>{},
|
undo : ()=>{},
|
||||||
redo : ()=>{},
|
redo : ()=>{},
|
||||||
historySize : ()=>{},
|
historySize : ()=>{},
|
||||||
cursorPos : {}
|
updateEditorTheme : ()=>{},
|
||||||
|
cursorPos : {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState : function() {
|
getInitialState : function() {
|
||||||
return {
|
return {
|
||||||
renderer : this.props.renderer,
|
renderer : this.props.renderer,
|
||||||
snippets : []
|
themeSelector : false,
|
||||||
|
snippets : []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -95,6 +100,31 @@ const Snippetbar = createClass({
|
|||||||
this.props.onInject(injectedText);
|
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 <div className='themeSelector'>
|
||||||
|
<select value={this.props.currentEditorTheme} onChange={this.changeTheme} onMouseDown={(this.changeTheme)}>
|
||||||
|
{EditorThemes.map((theme, key)=>{
|
||||||
|
return <option key={key} value={theme}>{theme}</option>;
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>;
|
||||||
|
},
|
||||||
|
|
||||||
renderSnippetGroups : function(){
|
renderSnippetGroups : function(){
|
||||||
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
|
const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view);
|
||||||
|
|
||||||
@@ -124,6 +154,12 @@ const Snippetbar = createClass({
|
|||||||
<i className='fas fa-redo' />
|
<i className='fas fa-redo' />
|
||||||
</div>
|
</div>
|
||||||
<div className='divider'></div>
|
<div className='divider'></div>
|
||||||
|
<div className={`editorTool editorTheme ${this.state.themeSelector ? 'active' : ''}`}
|
||||||
|
onClick={this.toggleThemeSelector} >
|
||||||
|
<i className='fas fa-palette' />
|
||||||
|
</div>
|
||||||
|
{this.state.themeSelector && this.renderThemeSelector()}
|
||||||
|
<div className='divider'></div>
|
||||||
<div className={cx('text', { selected: this.props.view === 'text' })}
|
<div className={cx('text', { selected: this.props.view === 'text' })}
|
||||||
onClick={()=>this.props.onViewChange('text')}>
|
onClick={()=>this.props.onViewChange('text')}>
|
||||||
<i className='fa fa-beer' />
|
<i className='fa fa-beer' />
|
||||||
@@ -196,5 +232,4 @@ const SnippetGroup = createClass({
|
|||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,6 +46,15 @@
|
|||||||
color : black;
|
color : black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.editorTheme{
|
||||||
|
.tooltipLeft('Editor Themes');
|
||||||
|
font-size : 0.75em;
|
||||||
|
color : black;
|
||||||
|
&.active{
|
||||||
|
color : white;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
}
|
||||||
&.divider {
|
&.divider {
|
||||||
background: linear-gradient(#000, #000) no-repeat center/1px 100%;
|
background: linear-gradient(#000, #000) no-repeat center/1px 100%;
|
||||||
width: 5px;
|
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{
|
.snippetBarButton{
|
||||||
height : @menuHeight;
|
height : @menuHeight;
|
||||||
|
|||||||
@@ -99,6 +99,24 @@ fs.emptyDirSync('./build');
|
|||||||
await fs.copy('./themes/assets', './build/assets');
|
await fs.copy('./themes/assets', './build/assets');
|
||||||
await fs.copy('./client/icons', './build/icons');
|
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//
|
//v==----------------------------- BUNDLE PACKAGES --------------------------------==v//
|
||||||
|
|
||||||
const bundles = await pack('./client/homebrew/homebrew.jsx', {
|
const bundles = await pack('./client/homebrew/homebrew.jsx', {
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ const CodeEditor = createClass({
|
|||||||
value : '',
|
value : '',
|
||||||
wrap : true,
|
wrap : true,
|
||||||
onChange : ()=>{},
|
onChange : ()=>{},
|
||||||
enableFolding : true
|
enableFolding : true,
|
||||||
|
editorTheme : 'default'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -91,6 +92,10 @@ const CodeEditor = createClass({
|
|||||||
} else {
|
} else {
|
||||||
this.codeMirror.setOption('foldOptions', false);
|
this.codeMirror.setOption('foldOptions', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(prevProps.editorTheme !== this.props.editorTheme){
|
||||||
|
this.codeMirror.setOption('theme', this.props.editorTheme);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
buildEditor : function() {
|
buildEditor : function() {
|
||||||
@@ -159,6 +164,7 @@ const CodeEditor = createClass({
|
|||||||
autoCloseTags : true,
|
autoCloseTags : true,
|
||||||
styleActiveLine : true,
|
styleActiveLine : true,
|
||||||
showTrailingSpace : false,
|
showTrailingSpace : false,
|
||||||
|
theme : this.props.editorTheme
|
||||||
// specialChars : / /,
|
// specialChars : / /,
|
||||||
// specialCharPlaceholder : function(char) {
|
// specialCharPlaceholder : function(char) {
|
||||||
// const el = document.createElement('span');
|
// const el = document.createElement('span');
|
||||||
@@ -406,7 +412,10 @@ const CodeEditor = createClass({
|
|||||||
//----------------------//
|
//----------------------//
|
||||||
|
|
||||||
render : function(){
|
render : function(){
|
||||||
return <div className='codeEditor' ref='editor' style={this.props.style}/>;
|
return <>
|
||||||
|
<link href={`../homebrew/cm-themes/${this.props.editorTheme}.css`} rel='stylesheet' />
|
||||||
|
<div className='codeEditor' ref='editor' style={this.props.style}/>
|
||||||
|
</>;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
88
themes/codeMirror/customEditorStyles.less
Normal file
88
themes/codeMirror/customEditorStyles.less
Normal file
@@ -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';
|
||||||
|
}
|
||||||
|
}
|
||||||
68
themes/codeMirror/editorThemes.json
Normal file
68
themes/codeMirror/editorThemes.json
Normal file
@@ -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"
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user