mirror of
https://github.com/urbit/shrub.git
synced 2024-12-20 01:01:37 +03:00
post: refactored post-input into input and editor
This commit is contained in:
parent
5b68df5e3d
commit
8707816d25
109
pkg/interface/src/apps/post/components/lib/post-editor.js
Normal file
109
pkg/interface/src/apps/post/components/lib/post-editor.js
Normal 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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
props.api.addPost(props.resource.ship, props.resource.name, post);
|
||||
this.editor.setValue('');
|
||||
this.setState({
|
||||
inCodeMode: false
|
||||
}, () => {
|
||||
props.api.addPost(props.resource.ship, props.resource.name, post);
|
||||
});
|
||||
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"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user