Renamed /src to /frontend

This commit is contained in:
Jori Lallo
2016-07-24 15:32:31 -07:00
parent 19da05eee7
commit d2187c4b10
147 changed files with 10 additions and 10 deletions

View File

@@ -0,0 +1,159 @@
import React from 'react';
import { observer } from 'mobx-react';
import Codemirror from 'react-codemirror';
import 'codemirror/mode/gfm/gfm';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/addon/edit/continuelist';
import 'codemirror/addon/display/placeholder.js';
import Dropzone from 'react-dropzone';
import ClickablePadding from './components/ClickablePadding';
import styles from './MarkdownEditor.scss';
import './codemirror.scss';
import { client } from 'utils/ApiClient';
@observer
class MarkdownEditor extends React.Component {
static propTypes = {
text: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired,
replaceText: React.PropTypes.func.isRequired,
onSave: React.PropTypes.func.isRequired,
// This is actually not used but it triggers
// re-render to help with CodeMirror focus issues
preview: React.PropTypes.bool,
}
getEditorInstance = () => {
return this.refs.editor.getCodeMirror();
}
onChange = (newText) => {
if (newText !== this.props.text) {
this.props.onChange(newText);
}
}
onDropAccepted = (files) => {
const file = files[0];
const editor = this.getEditorInstance();
const cursorPosition = editor.getCursor();
const insertOnNewLine = cursorPosition.ch !== 0;
let newCursorPositionLine;
// Lets set up the upload text
const pendingUploadTag = `![${file.name}](Uploading...)`;
if (insertOnNewLine) {
editor.replaceSelection('\n' + pendingUploadTag + '\n');
newCursorPositionLine = cursorPosition.line + 3;
} else {
editor.replaceSelection(pendingUploadTag + '\n');
newCursorPositionLine = cursorPosition.line + 2;
}
editor.setCursor(newCursorPositionLine, 0);
client.post('/user.s3Upload', {
kind: file.type,
size: file.size,
filename: file.name,
})
.then(response => {
const data = response.data;
// Upload using FormData API
let formData = new FormData();
for (let key in data.form) {
formData.append(key, data.form[key]);
}
if (file.blob) {
formData.append('file', file.file);
} else {
formData.append('file', file);
}
fetch(data.upload_url, {
method: 'post',
body: formData
})
.then(s3Response => {
this.props.replaceText({
original: pendingUploadTag,
new: `![${file.name}](${data.asset.url})`
});
editor.setCursor(newCursorPositionLine, 0);
})
.catch(err => {
this.props.replaceText({
original: pendingUploadTag,
new: '',
});
editor.setCursor(newCursorPositionLine, 0);
});
});
}
onPaddingTopClick = () => {
const cm = this.getEditorInstance();
cm.setCursor(0, 0);
cm.focus();
}
onPaddingBottomClick = () => {
const cm = this.getEditorInstance();
cm.setCursor(cm.lineCount(), 0);
cm.focus();
}
render = () => {
const options = {
readOnly: false,
lineNumbers: false,
mode: 'gfm',
matchBrackets: true,
lineWrapping: true,
viewportMargin: Infinity,
scrollbarStyle: 'null',
theme: 'atlas',
extraKeys: {
Enter: 'newlineAndIndentContinueMarkdownList',
"Ctrl-Enter": this.props.onSave,
"Cmd-Enter": this.props.onSave,
"Cmd-Esc": this.props.onCancel,
"Ctrl-Esc": this.props.onCancel,
// "Cmd-Shift-p": this.props.togglePreview,
// "Ctrl-Shift-p": this.props.togglePreview,
},
placeholder: "# Start with a title...",
};
return (
<Dropzone
onDropAccepted={this.onDropAccepted}
disableClick={true}
multiple={false}
accept={'image/*'}
className={styles.container}
>
<ClickablePadding onClick={ this.onPaddingTopClick } />
<Codemirror
value={this.props.text}
onChange={this.onChange}
options={options}
ref="editor"
className={styles.codeMirrorContainer}
/>
<ClickablePadding onClick={ this.onPaddingBottomClick } />
</Dropzone>
);
}
}
export default MarkdownEditor;

View File

@@ -0,0 +1,29 @@
.container {
display: flex;
flex: 1;
flex-direction: column;
font-weight: 400;
font-size: 1em;
line-height: 1.5em;
padding: 0 3em;
max-width: 50em;
}
.codeMirrorContainer {
width: 100%;
}
@media all and (max-width: 2000px) and (min-width: 960px) {
.container {
// margin-top: 48px;
font-size: 1.1em;
}
}
@media all and (max-width: 960px) {
.container {
font-size: 0.9em;
}
}

View File

@@ -0,0 +1,59 @@
@import '~styles/constants.scss';
:global {
/* Custom styling */
.cm-s-atlas.CodeMirror {
background: #fff;
color: #202020;
font-family: 'Atlas Typewriter', 'Menlo', 'Cousine', 'Monaco', monospace;
font-weight: 300;
height: auto; // This will break layout for some reason. TODO: investigate
width: 100%;
}
// Use Menlo for stronger weight
.cm-s-atlas .cm-header { font-family: 'Menlo', 'Cousine', 'Monaco', monospace; }
/* Disable ondrag cursor for file uploads */
.cm-s-atlas div.CodeMirror-dragcursors {
visibility: hidden;
}
.cm-s-atlas .CodeMirror-line::selection,
.cm-s-atlas .CodeMirror-line > span::selection,
.cm-s-atlas .CodeMirror-line > span > span::selection {
background: #90CAF9;
}
.cm-s-atlas .CodeMirror-line::-moz-selection, .cm-s-atlas .CodeMirror-line > span::-moz-selection, .cm-s-atlas .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }
.cm-s-atlas .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }
.cm-s-atlas .CodeMirror-guttermarker { color: #ac4142; }
.cm-s-atlas .CodeMirror-guttermarker-subtle { color: #b0b0b0; }
.cm-s-atlas .CodeMirror-linenumber { color: #b0b0b0; }
.cm-s-atlas .CodeMirror-cursor {
border-left: 2px solid #2196F3;
}
.cm-s-atlas span.cm-quote {
font-style: italic;
}
.cm-s-atlas span.cm-comment { color: #969896; }
.cm-s-atlas span.cm-atom { color: #0086b3; }
.cm-s-atlas span.cm-number { color: $textColor; }
.cm-s-atlas span.cm-property, .cm-s-atlas span.cm-attribute { color: $textColor; }
.cm-s-atlas span.cm-keyword { color: #a71d5d; }
.cm-s-atlas span.cm-string { color: #df5000; }
.cm-s-atlas span.cm-variable { color: $textColor; }
.cm-s-atlas span.cm-variable-2 { color: $textColor; }
.cm-s-atlas span.cm-def { color: $textColor; }
.cm-s-atlas span.cm-bracket { color: #202020; }
.cm-s-atlas span.cm-tag { color: #ac4142; }
.cm-s-atlas span.cm-link { color: $actionColor; }
.cm-s-atlas span.cm-error { background: #ac4142; color: #505050; }
.cm-s-atlas .CodeMirror-activeline-background { background: #DDDCDC; }
.cm-s-atlas .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
.cm-s-atlas .CodeMirror-placeholder { color: rgba(0, 0, 0, 0.5); font-weight: bold; }
}

View File

@@ -0,0 +1,18 @@
import React from 'react';
import styles from './ClickablePadding.scss';
const ClickablePadding = (props) => {
return (
<div
className={ styles.container }
onClick={ props.onClick }
>&nbsp;</div>
)
};
ClickablePadding.propTypes = {
onClick: React.PropTypes.func,
};
export default ClickablePadding;

View File

@@ -0,0 +1,10 @@
.container {
padding-top: 50px;
cursor: text;
}
@media all and (max-width: 960px) {
.container {
padding-top: 50px;
}
}

View File

@@ -0,0 +1,2 @@
import ClickablePadding from './ClickablePadding';
export default ClickablePadding;

View File

@@ -0,0 +1,2 @@
import MarkdownEditor from './MarkdownEditor';
export default MarkdownEditor;