Skip to content

Commit 4c2bd61

Browse files
authored
Merge pull request #26 from xsnippet/lang-bar
Post snippet
2 parents c3bbc3e + 5161e4e commit 4c2bd61

File tree

7 files changed

+126
-25
lines changed

7 files changed

+126
-25
lines changed

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"components": ["Link"],
99
"specialLink": ["to"]
1010
}],
11-
"react/prop-types": [0]
11+
"react/prop-types": [0],
12+
"jsx-a11y/click-events-have-key-events": [0]
1213
}
1314
}

src/actions/index.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,16 @@ export const fetchSyntaxes = dispatch => (
3030
.then(response => response.json())
3131
.then(json => dispatch(setSyntaxes(json)))
3232
);
33+
34+
export const postSnippet = snippet => dispatch => (
35+
fetch('http://api.xsnippet.org/snippets', {
36+
method: 'POST',
37+
headers: {
38+
Accept: 'application/json',
39+
'Content-Type': 'application/json',
40+
},
41+
body: JSON.stringify(snippet),
42+
})
43+
.then(response => response.json())
44+
.then(json => dispatch(setSnippet(json)))
45+
);

src/components/NewSnippet.jsx

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,89 @@
11
import React from 'react';
2+
import { connect } from 'react-redux';
23
import { Controlled as CodeMirror } from 'react-codemirror2';
34

45
import 'codemirror/lib/codemirror.css';
56

67
import Title from './common/Title';
78
import Input from './common/Input';
89
import Syntaxes from './Syntaxes';
10+
import * as actions from '../actions';
911

1012
import '../styles/NewSnippet.styl';
1113

1214
class NewSnippet extends React.Component {
13-
constructor() {
14-
super();
15-
this.state = { code: '' };
15+
constructor(props) {
16+
super(props);
17+
this.state = {
18+
content: '',
19+
title: '',
20+
tags: [],
21+
syntax: '', // eslint-disable-line react/no-unused-state
22+
};
23+
this.postSnippet = this.postSnippet.bind(this);
24+
this.onSyntaxClick = this.onSyntaxClick.bind(this);
25+
this.onInputChange = this.onInputChange.bind(this);
1626
}
27+
28+
onSyntaxClick(syntax) {
29+
this.setState({ syntax }); // eslint-disable-line react/no-unused-state
30+
}
31+
32+
onInputChange(e) {
33+
const { name } = e.target;
34+
let { value } = e.target;
35+
36+
if (name === 'tags') {
37+
value = value.split(',').map(item => item.trim());
38+
}
39+
40+
this.setState({ [name]: value });
41+
}
42+
43+
postSnippet(e) {
44+
e.preventDefault();
45+
const { dispatch } = this.props;
46+
dispatch(actions.postSnippet(this.state));
47+
}
48+
1749
render() {
1850
return (
1951
[
2052
<Title title="New snippet" key="New Snippet Title" />,
21-
<div className="new-snippet" key="New Snippet">
53+
<form className="new-snippet" key="New Snippet" onSubmit={this.postSnippet}>
2254
<div className="new-snippet-code-wrapper">
2355
<div className="new-snippet-code-header">
24-
<Input placeholder="Title" />
25-
<Input placeholder="Tags (separate tags by comma)" />
56+
<Input
57+
placeholder="Title"
58+
name="title"
59+
onChangeHandler={this.onInputChange}
60+
value={this.state.title}
61+
/>
62+
<Input
63+
placeholder="Tags (separate tags by comma)"
64+
name="tags"
65+
onChangeHandler={this.onInputChange}
66+
value={this.state.tags.toString()}
67+
/>
2668
</div>
2769
<div className="new-snippet-code">
2870
<CodeMirror
29-
value={this.state.code}
30-
options={{ lineNumbers: false }}
31-
onBeforeChange={(editor, data, code) => {
32-
this.setState({ code });
33-
}}
71+
value={this.state.content}
72+
options={{ lineNumbers: true }}
73+
onBeforeChange={(editor, data, content) => { this.setState({ content }); }}
3474
/>
3575
<div className="new-snippet-code-bottom-bar">
36-
<button>POST</button>
76+
<input type="submit" value="POST" />
3777
</div>
3878
</div>
3979
</div>
4080
<div className="new-snippet-lang-wrapper">
41-
<Syntaxes />
81+
<Syntaxes onClick={this.onSyntaxClick} />
4282
</div>
43-
</div>,
83+
</form>,
4484
]
4585
);
4686
}
4787
}
4888

49-
export default NewSnippet;
89+
export default connect()(NewSnippet);

src/components/Syntaxes.jsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,48 @@ import Input from './common/Input';
66
import * as actions from '../actions';
77

88
class Syntaxes extends React.Component {
9+
constructor(props) {
10+
super(props);
11+
this.state = { activeIndex: -1 };
12+
this.onClickHandler = this.onClickHandler.bind(this);
13+
}
14+
915
componentDidMount() {
1016
const { dispatch } = this.props;
1117
dispatch(actions.fetchSyntaxes);
1218
}
1319

20+
onClickHandler(e) {
21+
const { index, syntax } = e.target.dataset;
22+
23+
this.setState({ activeIndex: Number(index) });
24+
this.props.onClick(syntax);
25+
}
26+
1427
render() {
1528
const { syntaxes } = this.props;
1629

1730
return (
1831
[
19-
<div className="new-snippet-lang-header">
32+
<div className="new-snippet-lang-header" key="Syntax input">
2033
<Input placeholder="Type to search..." />
2134
</div>,
22-
<div className="new-snippet-lang-list-wrapper">
35+
<div className="new-snippet-lang-list-wrapper" key="Syntax list">
2336
<Scrollbars>
24-
<ul className="new-snippet-lang-list">
25-
{syntaxes.map(syntax => <li className="new-snippet-lang-item">{syntax}</li>)}
37+
<ul className="new-snippet-lang-list" onClick={this.onClickHandler} role="presentation">
38+
{syntaxes.map((syntax, index) => {
39+
const active = this.state.activeIndex === index ? 'active' : '';
40+
return (
41+
<li
42+
className={`new-snippet-lang-item ${active}`}
43+
data-syntax={syntax}
44+
data-index={index}
45+
key={syntax}
46+
>
47+
{syntax}
48+
</li>
49+
);
50+
})}
2651
</ul>
2752
</Scrollbars>
2853
</div>,

src/components/common/Input.jsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,39 @@ import PropTypes from 'prop-types';
33

44
import '../../styles/common/Input.styl';
55

6-
const Input = ({ additionalClass, placeholder, value }) => (
7-
<input className={`input ${additionalClass}`} placeholder={placeholder} value={value} />
8-
);
6+
const Input = (props) => {
7+
const {
8+
name, type, value, placeholder, additionalClass, onChangeHandler,
9+
} = props;
10+
11+
return (
12+
<input
13+
className={`input ${additionalClass}`}
14+
placeholder={placeholder}
15+
name={name}
16+
type={type}
17+
value={value}
18+
onChange={onChangeHandler}
19+
/>
20+
);
21+
};
922

1023
Input.propTypes = {
1124
additionalClass: PropTypes.string,
1225
placeholder: PropTypes.string,
1326
value: PropTypes.string,
27+
name: PropTypes.string,
28+
type: PropTypes.string,
29+
onChangeHandler: PropTypes.func,
1430
};
1531

1632
Input.defaultProps = {
1733
additionalClass: '',
1834
placeholder: 'Enter text',
1935
value: '',
36+
name: 'input',
37+
type: 'text',
38+
onChangeHandler: () => {},
2039
};
2140

2241
export default Input;

src/styles/NewSnippet.styl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ lang-bar-width = 230px
2121
&-code
2222
flex: 1
2323
position: relative
24-
padding: 20px 20px 63px 20px
24+
padding: 0 20px 63px 0
2525
&-wrapper
2626
display: flex
2727
flex-flow: column nowrap
@@ -40,7 +40,7 @@ lang-bar-width = 230px
4040
text-align: right
4141
padding: 5px
4242
border-top: 1px solid border-light
43-
& button
43+
& > input
4444
border: none
4545
background-color: button-normal
4646
color: text-light

src/styles/common/overwrite.styl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
.CodeMirror
55
height: 100% !important
66
font-family: font-ubuntu-mono !important
7+
8+
.new-snippet .react-codemirror2,
9+
.new-snippet .CodeMirror
710
color: text-dark !important
811

912
.CodeMirror-gutter

0 commit comments

Comments
 (0)