post: refactored post-input into input and editor

This commit is contained in:
Logan Allen 2020-06-24 14:00:44 -04:00
parent 5b68df5e3d
commit 8707816d25
3 changed files with 136 additions and 159 deletions

View File

@ -0,0 +1,109 @@
import React, { Component } from 'react';
import { UnControlled as CodeEditor } from 'react-codemirror2';
import CodeMirror from 'codemirror';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/addon/display/placeholder';
import 'codemirror/lib/codemirror.css';
const BROWSER_REGEX =
new RegExp(String(!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i));
const MARKDOWN_CONFIG = {
name: 'markdown',
tokenTypeOverrides: {
header: 'presentation',
quote: 'presentation',
list1: 'presentation',
list2: 'presentation',
list3: 'presentation',
hr: 'presentation',
image: 'presentation',
imageAltText: 'presentation',
imageMarker: 'presentation',
formatting: 'presentation',
linkInline: 'presentation',
linkEmail: 'presentation',
linkText: 'presentation',
linkHref: 'presentation'
}
};
export default class PostEditor extends Component {
constructor(props) {
super(props);
this.editor = null;
}
componentDidUpdate(prevProps) {
const { props } = this;
if (!props.inCodeMode) {
this.editor.setOption('mode', MARKDOWN_CONFIG);
this.editor.setOption('placeholder', this.props.placeholder);
} else {
this.editor.setOption('mode', null);
this.editor.setOption('placeholder', 'Code...');
}
const value = this.editor.getValue();
// Force redraw of placeholder
if(value.length === 0) {
this.editor.setValue(' ');
this.editor.setValue('');
}
}
submit() {
if(!this.editor) {
return;
}
let editorMessage = this.editor.getValue();
if (editorMessage === '') {
return;
}
this.props.submit(editorMessage);
this.editor.setValue('');
}
render() {
const { props } = this;
const codeTheme = props.inCodeMode ? ' code' : '';
const options = {
mode: MARKDOWN_CONFIG,
theme: 'tlon' + codeTheme,
lineNumbers: false,
lineWrapping: true,
scrollbarStyle: 'native',
cursorHeight: 0.85,
placeholder: props.inCodeMode ? 'Code...' : props.placeholder,
extraKeys: {
'Enter': () => {
this.submit();
}
}
};
return (
<div
className="chat fr h-100 flex bg-gray0-d lh-copy pl2 w-100 items-center"
style={{ flexGrow: 1, maxHeight: '224px', width: 'calc(100% - 72px)' }}
>
<CodeEditor
options={options}
editorDidMount={(editor) => {
this.editor = editor;
if (BROWSER_REGEX.test(navigator.userAgent)) {
editor.focus();
}
}}
/>
</div>
);
}
}

View File

@ -1,91 +1,30 @@
import React, { Component } from 'react';
import _ from 'lodash';
import moment from 'moment';
import { UnControlled as CodeEditor } from 'react-codemirror2';
import CodeMirror from 'codemirror';
import 'codemirror/mode/markdown/markdown';
import 'codemirror/addon/display/placeholder';
import 'codemirror/lib/codemirror.css';
import { Sigil } from '../../../../lib/sigil';
import PostEditor from './post-editor';
import { uxToHex } from '../../../../lib/util';
const MARKDOWN_CONFIG = {
name: 'markdown',
tokenTypeOverrides: {
header: 'presentation',
quote: 'presentation',
list1: 'presentation',
list2: 'presentation',
list3: 'presentation',
hr: 'presentation',
image: 'presentation',
imageAltText: 'presentation',
imageMarker: 'presentation',
formatting: 'presentation',
linkInline: 'presentation',
linkEmail: 'presentation',
linkText: 'presentation',
linkHref: 'presentation'
}
};
const URL_REGEX = new RegExp(String(/^((\w+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+)/.source));
export class PostInput extends Component {
constructor(props) {
super(props);
this.state = {
message: '',
inCodeMode: false
};
this.textareaRef = React.createRef();
this.messageSubmit = this.messageSubmit.bind(this);
this.submit = this.submit.bind(this);
this.toggleCode = this.toggleCode.bind(this);
this.editor = null;
moment.updateLocale('en', {
relativeTime : {
past: function(input) {
return input === 'just now'
? input
: input + ' ago';
},
s : 'just now',
future: 'in %s',
ss : '%d sec',
m: 'a minute',
mm: '%d min',
h: 'an hr',
hh: '%d hrs',
d: 'a day',
dd: '%d days',
M: 'a month',
MM: '%d months',
y: 'a year',
yy: '%d years'
}
toggleCode() {
this.setState({
inCodeMode: !this.state.inCodeMode
});
}
getLetterType(letter) {
if (letter.startsWith('/me ')) {
letter = letter.slice(4);
// remove insignificant leading whitespace.
// aces might be relevant to style.
while (letter[0] === '\n') {
letter = letter.slice(1);
}
return {
me: letter
};
} else if (this.isUrl(letter)) {
if (this.isUrl(letter)) {
return {
url: letter
};
@ -98,45 +37,33 @@ export class PostInput extends Component {
isUrl(string) {
try {
const websiteTest = new RegExp(String(/^((\w+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+)/.source)
);
return websiteTest.test(string);
return URL_REGEX.test(string);
} catch (e) {
return false;
}
}
messageSubmit() {
if(!this.editor) {
return;
}
submit(text) {
const { props, state } = this;
const editorMessage = this.editor.getValue();
console.log(editorMessage);
if (editorMessage === '') {
return;
}
if(state.code) {
if (state.inCodeMode) {
let post = props.api.createPost([
{
code: {
expression: editorMessage,
expression: text,
output: null
}
}
], props.parentIndex);
this.setState({
inCodeMode: false
}, () => {
props.api.addPost(props.resource.ship, props.resource.name, post);
this.editor.setValue('');
});
return;
}
let message = this.getLetterType(editorMessage);
let message = this.getLetterType(text);
let post = props.api.createPost([message], props.parentIndex);
props.api.addPost(props.resource.ship, props.resource.name, post);
@ -156,59 +83,12 @@ export class PostInput extends Component {
setTimeout(closure, 1000);
};
setTimeout(closure, 2000);*/
this.editor.setValue('');
}
toggleCode() {
if(this.state.code) {
this.setState({ code: false });
this.editor.setOption('mode', MARKDOWN_CONFIG);
this.editor.setOption('placeholder', this.props.placeholder);
} else {
this.setState({ code: true });
this.editor.setOption('mode', null);
this.editor.setOption('placeholder', 'Code...');
}
const value = this.editor.getValue();
// Force redraw of placeholder
if(value.length === 0) {
this.editor.setValue(' ');
this.editor.setValue('');
}
}
render() {
const { props, state } = this;
const codeTheme = state.code ? ' code' : '';
const options = {
mode: MARKDOWN_CONFIG,
theme: 'tlon' + codeTheme,
lineNumbers: false,
lineWrapping: true,
scrollbarStyle: 'native',
cursorHeight: 0.85,
placeholder: state.code ? 'Code...' : props.placeholder,
extraKeys: {
'Enter': () => {
this.messageSubmit();
if (this.state.code) {
this.toggleCode();
}
},
'Shift-3': cm =>
cm.getValue().length === 0
? this.toggleCode()
: CodeMirror.Pass
}
};
return (
<div className="chat pa3 cf flex black white-d bt b--gray4 b--gray1-d bg-white bg-gray0-d relative"
<div className="pa3 cf flex black white-d bt b--gray4 b--gray1-d bg-white bg-gray0-d relative"
style={{ flexGrow: 1 }}
>
<div
@ -225,28 +105,16 @@ export class PostInput extends Component {
color={`#000`}
/>
</div>
<div
className="fr h-100 flex bg-gray0-d lh-copy pl2 w-100 items-center"
style={{ flexGrow: 1, maxHeight: '224px', width: 'calc(100% - 72px)' }}
>
<CodeEditor
options={options}
editorDidMount={(editor) => {
this.editor = editor;
if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(
navigator.userAgent
)) {
editor.focus();
}
}}
/>
</div>
<PostEditor
inCodeMode={state.inCodeMode}
submit={this.submit}
placeholder='Post...' />
<div className="ml2 mr2"
style={{ height: '16px', width: '16px', flexBasis: 16, marginTop: 10 }}>
</div>
<div style={{ height: '16px', width: '16px', flexBasis: 16, marginTop: 10 }}>
<img
style={{ filter: state.code && 'invert(100%)', height: '100%', width: '100%' }}
style={{ filter: state.inCodeMode && 'invert(100%)', height: '100%', width: '100%' }}
onClick={this.toggleCode}
src="/~chat/img/CodeEval.png"
className="contrast-10-d bg-white bg-none-d ba b--gray1-d br1"

View File

@ -23,7 +23,7 @@ export class NewScreen extends Component {
if (prevProps !== props) {
const resource = `${window.ship}/${state.idName}`;
if (!!props.keys && props.keys.has(resource)) {
props.history.push('/~chat/room/' + resource);
props.history.push('/~post/room/' + resource);
}
}
}