add initial react app
This commit is contained in:
99
common/app/routes/Bonfires/components/Bonfires.jsx
Normal file
99
common/app/routes/Bonfires/components/Bonfires.jsx
Normal 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;
|
||||
62
common/app/routes/Bonfires/components/Results.jsx
Normal file
62
common/app/routes/Bonfires/components/Results.jsx
Normal 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;
|
||||
129
common/app/routes/Bonfires/components/SidePanel.jsx
Normal file
129
common/app/routes/Bonfires/components/SidePanel.jsx
Normal 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:
|
||||
{ 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;
|
||||
Reference in New Issue
Block a user