add initial react app

This commit is contained in:
Berkeley Martinez
2015-06-17 21:04:28 -07:00
parent bfddc0330f
commit a8540bee35
42 changed files with 299 additions and 244 deletions

View File

@@ -0,0 +1,99 @@
var React = require('react'),
// ## mixins
{ ObservableStateMixin } = require('thundercats'),
// ## components
SidePanel = require('./SidePanel.jsx'),
Results = require('./Results.jsx'),
Display = require('../displayCode'),
Editor = require('../editor'),
{ Grid, Row, Col } = require('react-bootstrap'),
// ## flux
BonfireActions = require('./Actions'),
BonfireStore = require('./Store');
var Bonfire = React.createClass({
mixins: [ObservableStateMixin],
contextTypes: {
makePath: React.PropTypes.func.isRequired,
replaceWith: React.PropTypes.func.isRequired
},
getObservable: function() {
return BonfireStore;
},
componentDidMount: function() {
// get history object
var his = typeof window !== 'undefined' ? window.history : null;
// spinal-case bonfireName
var bonfireName = this.state.name.toLowerCase().replace(/\s/g, '-');
// create proper URI from react-router
var path = this.context.makePath('bonfires', { bonfireName: bonfireName });
// if html5 push state exists, update URI
// else we are using hash location and should just cause a re render
if (his) {
his.replaceState({ path: path }, '', path);
} else {
this.context.replaceWith('bonfires', { bonfireName: bonfireName});
}
},
_onTestBonfire: function() {
BonfireActions.testUserCode({
userCode: this.state.userCode,
tests: this.state.tests
});
},
render: function() {
var {
name,
userCode,
difficulty,
description,
results,
display
} = this.state;
var brief = description.slice(0, 1).pop();
// convert bonfire difficulty from floating point string
// to integer.
var difficultyInt = Math.floor(+difficulty);
return (
<Grid>
<Row>
<Col
xs={ 12 }
md={ 4 }>
<SidePanel
name={ name }
brief={ brief }
difficulty={ difficultyInt }
onTestBonfire={ this._onTestBonfire }
description={ description.length > 1 ? description : [] }/>
<Display
value={ display }/>
<Results
results={ results }/>
</Col>
<Col
xs={ 12 }
md={ 8 }>
<Editor
onValueChange={ BonfireActions.setUserCode }
value={ userCode }/>
</Col>
</Row>
</Grid>
);
}
});
module.exports = Bonfire;

View File

@@ -0,0 +1,62 @@
var React = require('react'),
classNames = require('classnames'),
{ Grid, Row, Col } = require('react-bootstrap');
var Results = React.createClass({
propTypes: {
results: React.PropTypes.array
},
_renderText: function(text, textClass) {
return (
<Col
xs={ 11 }
className={ classNames(textClass) }>
{ text }
</Col>
);
},
_renderResult: function(results) {
return results.map(function(result, idx) {
var err = result.err;
var iconClass = {
'ion-close-circled big-error-icon': err,
'ion-checkmark-circled big-success-icon': !err
};
var textClass = {
'test-output wrappable': true,
'test-vertical-center': !err
};
return (
<div key={ idx }>
<Row>
<Col
xs={ 1 }
className='text-center'>
<i className={ classNames(iconClass) }></i>
</Col>
{ this._renderText(result.text, textClass) }
{ err ? this._renderText(err, textClass) : null }
</Row>
<div className='ten-pixel-break'></div>
</div>
);
}.bind(this));
},
render: function() {
var results = this.props.results;
if (!results || results.length && results.length === 0) {
return null;
}
return (
<Grid>
{ this._renderResult(this.props.results) }
</Grid>
);
}
});
module.exports = Results;

View File

@@ -0,0 +1,129 @@
var React = require('react'),
// ## components
{
Well,
Row,
Col,
Button,
} = require('react-bootstrap');
var SidePanel = React.createClass({
propTypes: {
name: React.PropTypes.string,
brief: React.PropTypes.string,
description: React.PropTypes.array,
difficulty: React.PropTypes.number,
onTestBonfire: React.PropTypes.func
},
getDefaultProps: function() {
return {
name: 'Welcome to Bonfires!',
difficulty: 5,
brief: 'This is a brief description'
};
},
getInitialState: function() {
return {
isMoreInfoOpen: false
};
},
_toggleMoreInfo: function() {
this.setState({
isMoreInfoOpen: !this.state.isMoreInfoOpen
});
},
_renderFlames: function() {
var difficulty = this.props.difficulty;
return [1, 2, 3, 4, 5].map(num => {
var className = 'ion-ios-flame';
if (num > difficulty) {
className += '-outline';
}
return (
<i
key={ num }
className={ className }/>
);
});
},
_renderMoreInfo: function(isDescription) {
var description = this.props.description.map((sentance, index) => {
return <p key={ index }>{ sentance }</p>;
});
if (isDescription && this.state.isMoreInfoOpen) {
return (
<Row>
<Col xs={ 12 }>
{ description }
</Col>
</Row>
);
}
return null;
},
_renderMoreInfoButton: function(isDescription) {
if (isDescription) {
return (
<Button
onClick={ this._toggleMoreInfo }
bsStyle='primary'
block={ true }
className='btn-primary-ghost'>
<span className='ion-arrow-down-b'></span>
More information
</Button>
);
}
return null;
},
render: function() {
var isDescription = this.props.description &&
this.props.description.length > 1;
return (
<div>
<h1 className='text-center'>{ this.props.name }</h1>
<h2 className='text-center'>
<div className='bonfire-flames'>
Difficulty:&nbsp;
{ this._renderFlames() }
</div>
</h2>
<Well>
<Row>
<Col xs={ 12 }>
<div className='bonfire-instructions'>
<p>{ this.props.brief }</p>
<div>
{ this._renderMoreInfo(isDescription) }
{ this._renderMoreInfoButton(isDescription) }
</div>
</div>
</Col>
</Row>
</Well>
<Button
bsStyle='primary'
block={ true }
className='btn-big'
onClick={ this.props.onTestBonfire }>
Run Code (ctrl + enter)
</Button>
<br />
</div>
);
}
});
module.exports = SidePanel;