Add reactify branch react components
This commit is contained in:
19
common/screens/App.jsx
Normal file
19
common/screens/App.jsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
var React = require('react'),
|
||||||
|
RouteHandler = require('react-router').RouteHandler,
|
||||||
|
|
||||||
|
// ## components
|
||||||
|
Nav = require('./nav'),
|
||||||
|
Footer = require('./footer');
|
||||||
|
|
||||||
|
var App = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Nav />
|
||||||
|
<RouteHandler />
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module.exports = App;
|
34
common/screens/Router.jsx
Normal file
34
common/screens/Router.jsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
var React = require('react'),
|
||||||
|
|
||||||
|
// react router
|
||||||
|
Router = require('react-router'),
|
||||||
|
Route = Router.Route,
|
||||||
|
// NotFound = Router.NotFoundRoute,
|
||||||
|
DefaultRoute = Router.DefaultRoute,
|
||||||
|
|
||||||
|
// # Components
|
||||||
|
App = require('./App.jsx'),
|
||||||
|
Bonfires = require('./bonfires');
|
||||||
|
|
||||||
|
var routes = (
|
||||||
|
<Route
|
||||||
|
name='app'
|
||||||
|
path='/'
|
||||||
|
handler={ App }>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
name='bonfires'
|
||||||
|
path='/bonfires/?:bonfireName?'
|
||||||
|
handler={ Bonfires } />
|
||||||
|
|
||||||
|
<DefaultRoute
|
||||||
|
handler={ Bonfires } />
|
||||||
|
</Route>
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = function(Location) {
|
||||||
|
return Router.create({
|
||||||
|
routes: routes,
|
||||||
|
location: Location
|
||||||
|
});
|
||||||
|
};
|
63
common/screens/bonfires/Actions.js
Normal file
63
common/screens/bonfires/Actions.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
var Action = require('thundercats').Action,
|
||||||
|
executeBonfire = require('./executeBonfire'),
|
||||||
|
getModel = require('../../utils/getModel'),
|
||||||
|
debug = require('debug')('freecc:common:bonfires');
|
||||||
|
|
||||||
|
var BonfireActions = Action.createActions([
|
||||||
|
'setUserCode',
|
||||||
|
'testUserCode',
|
||||||
|
'setResults',
|
||||||
|
'setDisplay',
|
||||||
|
'setBonfire',
|
||||||
|
'getBonfire',
|
||||||
|
'handleBonfireError',
|
||||||
|
'openCompletionModal'
|
||||||
|
]);
|
||||||
|
|
||||||
|
BonfireActions
|
||||||
|
.getBonfire
|
||||||
|
.subscribe(function(params) {
|
||||||
|
var Bonfire = getModel('bonfire');
|
||||||
|
var bonfireName = params.bonfireName ?
|
||||||
|
params.bonfireName.replace(/\-/g, ' ') :
|
||||||
|
'meet bonfire';
|
||||||
|
debug('getting bonfire for: ', bonfireName);
|
||||||
|
var regQuery = { name: { like: bonfireName, options: 'i' } };
|
||||||
|
Bonfire.find(
|
||||||
|
{ where: regQuery },
|
||||||
|
function(err, bonfire) {
|
||||||
|
if (err) {
|
||||||
|
return debug('bonfire get err', err);
|
||||||
|
}
|
||||||
|
if (!bonfire || bonfire.length < 1) {
|
||||||
|
return debug('404 no bonfire found for ', bonfireName);
|
||||||
|
}
|
||||||
|
bonfire = bonfire.pop();
|
||||||
|
if (bonfire) {
|
||||||
|
debug(
|
||||||
|
'found bonfire %s for route %s',
|
||||||
|
bonfire.name,
|
||||||
|
bonfireName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
BonfireActions.setBonfire(bonfire);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
BonfireActions
|
||||||
|
.testUserCode
|
||||||
|
.subscribe(function({ userCode, tests }) {
|
||||||
|
debug('test bonfire');
|
||||||
|
executeBonfire(userCode, tests, function(err, { output, results }) {
|
||||||
|
if (err) {
|
||||||
|
debug('error running tests', err);
|
||||||
|
return BonfireActions.setDisplay(err);
|
||||||
|
}
|
||||||
|
BonfireActions.setDisplay(output);
|
||||||
|
BonfireActions.setResults(results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BonfireActions;
|
99
common/screens/bonfires/Bonfires.jsx
Normal file
99
common/screens/bonfires/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/screens/bonfires/Results.jsx
Normal file
62
common/screens/bonfires/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/screens/bonfires/SidePanel.jsx
Normal file
129
common/screens/bonfires/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;
|
67
common/screens/bonfires/Store.js
Normal file
67
common/screens/bonfires/Store.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
var BonfiresActions = require('./Actions');
|
||||||
|
var { Store, setStateUtil } = require('thundercats');
|
||||||
|
|
||||||
|
var BonfiresStore = Store.create({
|
||||||
|
|
||||||
|
getInitialValue: function() {
|
||||||
|
return {
|
||||||
|
userCode: 'console.log(\'FreeCodeCamp!\')',
|
||||||
|
difficulty: 0,
|
||||||
|
description: [
|
||||||
|
'default state'
|
||||||
|
],
|
||||||
|
tests: [],
|
||||||
|
results: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getOperations: function() {
|
||||||
|
var {
|
||||||
|
setBonfire,
|
||||||
|
setUserCode,
|
||||||
|
setResults,
|
||||||
|
setDisplay
|
||||||
|
} = BonfiresActions;
|
||||||
|
|
||||||
|
return [
|
||||||
|
setBonfire
|
||||||
|
.map(function(bonfire) {
|
||||||
|
var {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
difficulty,
|
||||||
|
tests
|
||||||
|
} = bonfire;
|
||||||
|
var userCode = bonfire.challengeSeed;
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
userCode,
|
||||||
|
tests,
|
||||||
|
description,
|
||||||
|
difficulty
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.map(setStateUtil),
|
||||||
|
|
||||||
|
setUserCode
|
||||||
|
.map(function(userCode) {
|
||||||
|
return { userCode };
|
||||||
|
})
|
||||||
|
.map(setStateUtil),
|
||||||
|
|
||||||
|
setDisplay
|
||||||
|
.map(function(display) {
|
||||||
|
return { display };
|
||||||
|
})
|
||||||
|
.map(setStateUtil),
|
||||||
|
|
||||||
|
setResults
|
||||||
|
.map(function(results) {
|
||||||
|
return { results };
|
||||||
|
})
|
||||||
|
.map(setStateUtil)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BonfiresStore;
|
27
common/screens/bonfires/executeBonfire.js
Normal file
27
common/screens/bonfires/executeBonfire.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
var debug = require('debug')('freecc:executebonfire');
|
||||||
|
var {
|
||||||
|
addTests,
|
||||||
|
runTests,
|
||||||
|
testCode
|
||||||
|
} = require('../../utils');
|
||||||
|
|
||||||
|
module.exports = executeBonfire;
|
||||||
|
|
||||||
|
function executeBonfire(userCode, tests, cb) {
|
||||||
|
|
||||||
|
// TODO: move this into componentDidMount
|
||||||
|
// ga('send', 'event', 'Bonfire', 'ran-code', bonfireName);
|
||||||
|
var testSalt = Math.random();
|
||||||
|
var { preppedCode, userTests } = addTests(userCode, tests, testSalt);
|
||||||
|
|
||||||
|
debug('sending code to web worker for testing');
|
||||||
|
testCode(preppedCode, function(err, data) {
|
||||||
|
if (err) { return cb(err); }
|
||||||
|
var results = runTests(userTests, data, testSalt);
|
||||||
|
debug('testing complete', results);
|
||||||
|
cb(null, {
|
||||||
|
output: data.output,
|
||||||
|
results
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
1
common/screens/bonfires/index.js
Normal file
1
common/screens/bonfires/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./Bonfires.jsx');
|
34
common/screens/context/Actions.js
Normal file
34
common/screens/context/Actions.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
var debug = require('debug')('freecc:context'),
|
||||||
|
BonfireActions = require('../bonfires/Actions'),
|
||||||
|
BonfireStore = require('../bonfires/Store');
|
||||||
|
|
||||||
|
var {
|
||||||
|
Action,
|
||||||
|
waitFor
|
||||||
|
} = require('thundercats');
|
||||||
|
|
||||||
|
var actions = Action.createActions([
|
||||||
|
'setContext',
|
||||||
|
'renderToUser'
|
||||||
|
]);
|
||||||
|
|
||||||
|
actions
|
||||||
|
.setContext
|
||||||
|
.filter(function(ctx) {
|
||||||
|
return ctx.state.path.indexOf('/bonfire') !== -1;
|
||||||
|
})
|
||||||
|
.subscribe(function(ctx) {
|
||||||
|
debug('set ctx');
|
||||||
|
BonfireActions.getBonfire(ctx.state.params);
|
||||||
|
waitFor(BonfireStore)
|
||||||
|
.firstOrDefault()
|
||||||
|
.catch(function(err) {
|
||||||
|
// handle timeout error
|
||||||
|
debug('err', err);
|
||||||
|
})
|
||||||
|
.subscribe(function() {
|
||||||
|
actions.renderToUser(ctx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = actions;
|
18
common/screens/context/Store.js
Normal file
18
common/screens/context/Store.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
var Store = require('thundercats').Store,
|
||||||
|
ContextActions = require('./Actions');
|
||||||
|
|
||||||
|
var ContextStore = Store.create({
|
||||||
|
getInitialValue: function() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
getOperations: function() {
|
||||||
|
return ContextActions
|
||||||
|
.renderToUser
|
||||||
|
.map(function(ctx) {
|
||||||
|
return { value: ctx };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ContextStore;
|
51
common/screens/displayCode/Display.jsx
Normal file
51
common/screens/displayCode/Display.jsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
var React = require('react'),
|
||||||
|
Tailspin = require('tailspin');
|
||||||
|
|
||||||
|
var Editor = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
value: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
value: [
|
||||||
|
'/**',
|
||||||
|
'* Your output will go here.',
|
||||||
|
'* Console.log() -type statements',
|
||||||
|
'* will appear in your browser\'s',
|
||||||
|
'* DevTools JavaScript console.',
|
||||||
|
'**/'
|
||||||
|
].join('\n')
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var value = this.props.value;
|
||||||
|
var options = {
|
||||||
|
lineNumbers: false,
|
||||||
|
lineWrapping: true,
|
||||||
|
mode: 'text',
|
||||||
|
readOnly: 'noCursor',
|
||||||
|
textAreaClassName: 'hide-textarea',
|
||||||
|
theme: 'monokai',
|
||||||
|
value: value
|
||||||
|
};
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
setSize: ['100%', '100%']
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className='code'>
|
||||||
|
<div className='form-group codeMirrorView'>
|
||||||
|
<Tailspin
|
||||||
|
{ ...options }
|
||||||
|
config={ config }/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Editor;
|
1
common/screens/displayCode/index.js
Normal file
1
common/screens/displayCode/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./Display.jsx');
|
91
common/screens/editor/Editor.jsx
Normal file
91
common/screens/editor/Editor.jsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
var React = require('react'),
|
||||||
|
debug = require('debug')('freecc:comp:editor'),
|
||||||
|
jshint = require('jshint').JSHINT,
|
||||||
|
Tailspin = require('tailspin');
|
||||||
|
|
||||||
|
var Editor = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
onValueChange: React.PropTypes.func,
|
||||||
|
value: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
value: 'console.log(\'freeCodeCamp is awesome\')'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
value: this.props.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var options = {
|
||||||
|
autoCloseBrackets: true,
|
||||||
|
gutters: ['CodeMirror-lint-markers'],
|
||||||
|
lint: true,
|
||||||
|
linter: jshint,
|
||||||
|
lineNumbers: true,
|
||||||
|
lineWrapping: true,
|
||||||
|
mode: 'javascript',
|
||||||
|
matchBrackets: true,
|
||||||
|
runnable: true,
|
||||||
|
scrollbarStyle: 'null',
|
||||||
|
theme: 'monokai',
|
||||||
|
textAreaClassName: 'hide-textarea',
|
||||||
|
value: this.state.value,
|
||||||
|
onChange: e => {
|
||||||
|
this.setState({ value: e.target.value});
|
||||||
|
if (typeof this.props.onValueChange === 'function') {
|
||||||
|
this.props.onValueChange(e.target.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
setSize: ['100%', 'auto'],
|
||||||
|
extraKeys: {
|
||||||
|
Tab: function(cm) {
|
||||||
|
debug('tab pressed');
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('add');
|
||||||
|
} else {
|
||||||
|
var spaces = new Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||||
|
cm.replaceSelection(spaces);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Shift-Tab': function(cm) {
|
||||||
|
debug('shift-tab pressed');
|
||||||
|
if (cm.somethingSelected()) {
|
||||||
|
cm.indentSelection('subtract');
|
||||||
|
} else {
|
||||||
|
var spaces = new Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||||
|
cm.replaceSelection(spaces);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Ctrl-Enter': function() {
|
||||||
|
debug('C-enter pressed');
|
||||||
|
// execute bonfire action
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id='mainEditorPanel'>
|
||||||
|
<form className='code'>
|
||||||
|
<div className='form-group codeMirrorView'>
|
||||||
|
<Tailspin
|
||||||
|
{ ...options }
|
||||||
|
config={ config }/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Editor;
|
1
common/screens/editor/index.js
Normal file
1
common/screens/editor/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./Editor.jsx');
|
106
common/screens/footer/Footer.jsx
Normal file
106
common/screens/footer/Footer.jsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
var React = require('react');
|
||||||
|
|
||||||
|
var Footer = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<div className='fcc-footer'>
|
||||||
|
<div className='col-xs-12 hidden-xs hidden-sm'>
|
||||||
|
<a
|
||||||
|
href='http://blog.freecodecamp.com'
|
||||||
|
target='_blank' className='ion-speakerphone'>
|
||||||
|
Blog
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
ref='http://www.twitch.tv/freecodecamp'
|
||||||
|
target='_blank' className='ion-social-twitch-outline'>
|
||||||
|
Twitch
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://github.com/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-github'>
|
||||||
|
Github
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://twitter.com/freecodecamp'
|
||||||
|
target='_blank' className='ion-social-twitter'>
|
||||||
|
Twitter
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://facebook.com/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-facebook'>
|
||||||
|
Facebook
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
ref='/learn-to-code'
|
||||||
|
className='ion-information-circled'>
|
||||||
|
About
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/privacy'
|
||||||
|
className='ion-locked'>
|
||||||
|
Privacy
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div className='col-xs-12 visible-xs visible-sm'>
|
||||||
|
<a
|
||||||
|
href='http://blog.freecodecamp.com'
|
||||||
|
target='_blank' className='ion-speakerphone'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp\'s Blog
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://www.twitch.tv/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-twitch-outline'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp Live Pair Programming on Twitch.tv
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://github.com/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-github'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp on GitHub
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://twitter.com/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-twitter'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp on Twitter
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='http://facebook.com/freecodecamp'
|
||||||
|
target='_blank'
|
||||||
|
className='ion-social-facebook'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp on Facebook
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/learn-to-code'
|
||||||
|
className='ion-information-circled'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
About Free Code Camp
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href='/privacy'
|
||||||
|
className='ion-locked'>
|
||||||
|
<span className='sr-only'>
|
||||||
|
Free Code Camp's Privacy Policy
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Footer;
|
1
common/screens/footer/index.js
Normal file
1
common/screens/footer/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./Footer.jsx');
|
81
common/screens/nav/Nav.jsx
Normal file
81
common/screens/nav/Nav.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
var React = require('react'),
|
||||||
|
bootStrap = require('react-bootstrap'),
|
||||||
|
Navbar = bootStrap.Navbar,
|
||||||
|
Nav = bootStrap.Nav,
|
||||||
|
NavItem = bootStrap.NavItem,
|
||||||
|
NavItemFCC = require('./NavItem.jsx');
|
||||||
|
|
||||||
|
var NavBarComp = React.createClass({
|
||||||
|
|
||||||
|
propTypes: { signedIn: React.PropTypes.bool },
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return { signedIn: false };
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderBrand: function() {
|
||||||
|
var fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
|
||||||
|
return (
|
||||||
|
<a href='/'>
|
||||||
|
<img
|
||||||
|
src={ fCClogo }
|
||||||
|
alt='learn to code javascript at Free Code Camp logo'
|
||||||
|
className='img-responsive nav-logo' />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderSignin: function() {
|
||||||
|
if (this.props.signedIn) {
|
||||||
|
return (
|
||||||
|
<NavItem
|
||||||
|
eventKey={ 2 }>
|
||||||
|
Show Picture
|
||||||
|
</NavItem>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<NavItemFCC
|
||||||
|
eventKey={ 2 }
|
||||||
|
href='/login'
|
||||||
|
aClassName='btn signup-btn signup-btn-nav'>
|
||||||
|
Sign In
|
||||||
|
</NavItemFCC>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Navbar
|
||||||
|
brand={ this._renderBrand() }
|
||||||
|
fixedTop={ true }
|
||||||
|
toggleNavKey={ 0 }
|
||||||
|
className='nav-height'>
|
||||||
|
<Nav
|
||||||
|
right={ true }
|
||||||
|
eventKey={ 0 }
|
||||||
|
className='hamburger-dropdown'>
|
||||||
|
<NavItem
|
||||||
|
eventKey={ 1 }
|
||||||
|
href='/Challenges'>
|
||||||
|
Challenges
|
||||||
|
</NavItem>
|
||||||
|
<NavItem
|
||||||
|
eventKey={ 1 }
|
||||||
|
href='Chat'>
|
||||||
|
Chat
|
||||||
|
</NavItem>
|
||||||
|
<NavItem
|
||||||
|
eventKey={ 2 }
|
||||||
|
href='/bonfires'>
|
||||||
|
Bonfires
|
||||||
|
</NavItem>
|
||||||
|
{ this._renderSignin() }
|
||||||
|
</Nav>
|
||||||
|
</Navbar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module.exports = NavBarComp;
|
66
common/screens/nav/NavItem.jsx
Normal file
66
common/screens/nav/NavItem.jsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
var React = require('react/addons');
|
||||||
|
var joinClasses = require('react-bootstrap/lib/utils/joinClasses');
|
||||||
|
var classSet = React.addons.classSet;
|
||||||
|
var BootstrapMixin = require('react-bootstrap').BootstrapMixin;
|
||||||
|
|
||||||
|
var NavItem = React.createClass({
|
||||||
|
mixins: [BootstrapMixin],
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
onSelect: React.PropTypes.func,
|
||||||
|
active: React.PropTypes.bool,
|
||||||
|
disabled: React.PropTypes.bool,
|
||||||
|
href: React.PropTypes.string,
|
||||||
|
title: React.PropTypes.string,
|
||||||
|
eventKey: React.PropTypes.any,
|
||||||
|
target: React.PropTypes.string
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function () {
|
||||||
|
return {
|
||||||
|
href: '#'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
var {
|
||||||
|
disabled,
|
||||||
|
active,
|
||||||
|
href,
|
||||||
|
title,
|
||||||
|
target,
|
||||||
|
children,
|
||||||
|
} = this.props,
|
||||||
|
props = this.props,
|
||||||
|
classes = {
|
||||||
|
'active': active,
|
||||||
|
'disabled': disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li {...props} className={joinClasses(props.className, classSet(classes))}>
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
title={title}
|
||||||
|
target={target}
|
||||||
|
className={ this.props.aClassName }
|
||||||
|
onClick={this.handleClick}
|
||||||
|
ref="anchor">
|
||||||
|
{ children }
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClick: function (e) {
|
||||||
|
if (this.props.onSelect) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!this.props.disabled) {
|
||||||
|
this.props.onSelect(this.props.eventKey, this.props.href, this.props.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = NavItem;
|
1
common/screens/nav/index.js
Normal file
1
common/screens/nav/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./Nav.jsx');
|
Reference in New Issue
Block a user