فهرست منبع

WIP: impl theme selector

Yuki Takei 8 سال پیش
والد
کامیت
bbca72d79d

+ 4 - 0
lib/views/_form.html

@@ -27,6 +27,10 @@
       ファイルを追加 ...
     </button>#}
 
+    <div class="pull-left">
+      <div id="page-editor-theme-selector"></div>
+    </div>
+
     <div class="pull-right form-inline page-form-setting" id="page-form-setting" data-slack-configured="{{ slackConfigured() }}">
       {% if slackConfigured() %}
       <span class="input-group extended-setting">

+ 22 - 2
resource/js/app.js

@@ -7,6 +7,7 @@ import CrowiRenderer from './util/CrowiRenderer';
 import HeaderSearchBox  from './components/HeaderSearchBox';
 import SearchPage       from './components/SearchPage';
 import PageEditor       from './components/PageEditor';
+import ThemeSelector    from './components/PageEditor/ThemeSelector';
 import PageListSearch   from './components/PageListSearch';
 import PageHistory      from './components/PageHistory';
 import PageComments     from './components/PageComments';
@@ -76,8 +77,6 @@ const onSaveSuccess = function(page) {
 const componentMappings = {
   'search-top': <HeaderSearchBox crowi={crowi} />,
   'search-page': <SearchPage crowi={crowi} />,
-  'page-editor': <PageEditor crowi={crowi} pageId={pageId} revisionId={pageRevisionId} pagePath={pagePath} markdown={entities.decodeHTML(pageContent)}
-                              onSaveSuccess={onSaveSuccess}/>,
   'page-list-search': <PageListSearch crowi={crowi} />,
   'page-comments-list': <PageComments pageId={pageId} revisionId={pageRevisionId} revisionCreatedAt= {pageRevisionCreatedAt} crowi={crowi} />,
   'page-attachment': <PageAttachment pageId={pageId} pageContent={pageContent} crowi={crowi} />,
@@ -106,6 +105,27 @@ if (elem) {
   ReactDOM.render(<PageCommentFormBehavior crowi={crowi} pageComments={componentInstances['page-comments-list']} />, elem);
 }
 
+// render PageEditor
+let pageEditor = null;
+const pageEditorElem = document.getElementById('page-editor');
+if (pageEditorElem) {
+  pageEditor = ReactDOM.render(
+    <PageEditor crowi={crowi} pageId={pageId} revisionId={pageRevisionId} pagePath={pagePath}
+        markdown={entities.decodeHTML(pageContent)}
+        onSaveSuccess={onSaveSuccess} />,
+    pageEditorElem
+  );
+}
+const themeSelectorElem = document.getElementById('page-editor-theme-selector');
+if (themeSelectorElem) {
+  ReactDOM.render(
+    <ThemeSelector onChange={(value) => { // set onChange event handler
+      pageEditor.setEditorTheme(value);
+    }} />,
+    themeSelectorElem
+  );
+}
+
 // render for admin
 const customCssEditorElem = document.getElementById('custom-css-editor');
 if (customCssEditorElem != null) {

+ 8 - 0
resource/js/components/PageEditor.js

@@ -60,6 +60,14 @@ export default class PageEditor extends React.Component {
     this.refs.editor.setCaretLine(line);
   }
 
+  /**
+   * set theme
+   * @param {string} theme name
+   */
+  setEditorTheme(name) {
+    this.refs.editor.setTheme(name);
+  }
+
   /**
    * the change event handler for `markdown` state
    * @param {string} value

+ 19 - 2
resource/js/components/PageEditor/Editor.js

@@ -21,7 +21,14 @@ require('codemirror/addon/fold/foldgutter.css');
 require('codemirror/addon/fold/markdown-fold');
 require('codemirror/addon/fold/brace-fold');
 require('codemirror/mode/gfm/gfm');
-require('codemirror/theme/eclipse.css');
+
+require('codemirror/theme/elegant.css');
+require('codemirror/theme/neo.css');
+require('codemirror/theme/mdn-like.css');
+require('codemirror/theme/material.css');
+require('codemirror/theme/monokai.css');
+require('codemirror/theme/twilight.css');
+
 
 import Dropzone from 'react-dropzone';
 
@@ -41,6 +48,7 @@ export default class Editor extends React.Component {
       value: this.props.value,
       dropzoneActive: false,
       isUploading: false,
+      theme: 'elegant',
     };
 
     this.getCodeMirror = this.getCodeMirror.bind(this);
@@ -90,6 +98,14 @@ export default class Editor extends React.Component {
     editor.setCursor({line: line-1});   // leave 'ch' field as null/undefined to indicate the end of line
   }
 
+  /**
+   * set theme
+   * @param {string} theme name
+   */
+  setTheme(name) {
+    this.setState({ theme: name });
+  }
+
   /**
    * remove overlay and set isUploading to false
    */
@@ -256,6 +272,7 @@ export default class Editor extends React.Component {
       height: 'calc(100% - 20px)'
     }
 
+    const theme = this.state.theme;
     return (
       <div style={flexContainer}>
         <Dropzone
@@ -282,7 +299,7 @@ export default class Editor extends React.Component {
             value={this.state.value}
             options={{
               mode: 'gfm',
-              theme: 'eclipse',
+              theme: theme,
               lineNumbers: true,
               tabSize: 4,
               indentUnit: 4,

+ 55 - 0
resource/js/components/PageEditor/ThemeSelector.js

@@ -0,0 +1,55 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+export default class ThemeSelector extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.availableThemes = [
+      'elegant', 'neo', 'mdn-like', 'material', 'monokai', 'twilight'
+    ]
+    
+    this.onChange = this.onChange.bind(this);
+  }
+
+  componentDidMount() {
+    this.init(this.props.value || this.availableThemes[0]);
+  }
+
+  init(value) {
+    this.inputEl.value = value;
+  }
+
+  onChange() {
+    if (this.props.onChange != null) {
+      this.props.onChange(this.inputEl.value);
+    }
+  }
+
+  render() {
+    const options = this.availableThemes.map((theme) => {
+      return <option key={theme} value={theme}>{theme}</option>;
+    });
+
+    return (
+      <FormGroup controlId="formControlsSelect">
+        <ControlLabel>Theme:</ControlLabel>
+        <FormControl componentClass="select" placeholder="select"
+            onChange={this.onChange}
+            inputRef={ el => this.inputEl=el }>
+
+          {options}
+
+        </FormControl>
+      </FormGroup>
+    )
+  }
+}
+
+ThemeSelector.propTypes = {
+  value: PropTypes.string,
+  onChange: PropTypes.func,
+};

+ 6 - 2
resource/js/util/Crowi.js

@@ -118,11 +118,15 @@ export default class Crowi {
   }
 
   setCaretLine(line) {
-    this.pageEditor.setCaretLine(line);
+    if (this.pageEditor != null) {
+      this.pageEditor.setCaretLine(line);
+    }
   }
 
   focusToEditor() {
-    this.pageEditor.focusToEditor();
+    if (this.pageEditor != null) {
+      this.pageEditor.focusToEditor();
+    }
   }
 
   clearDraft(path) {