Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save linuxenko/ab2fa9dc55d554b52a43 to your computer and use it in GitHub Desktop.
Save linuxenko/ab2fa9dc55d554b52a43 to your computer and use it in GitHub Desktop.
Build a Recipe Box [freeCodeCamp [Data Visualization]] (Challenge)
const FIXTURES = [
{
title : 'English-Muffin Egg Pizza',
ingredients : 'olive oil, tomato slices, hard-cooked eggs, grated mozzarella, oregano, kosher salt'
} , {
title : 'Prosciutto and Egg Panini',
ingredients : 'large eggs, salt, soft rolls, Swiss cheese '
} , {
title : 'Bagel and Cream Cheese With Tomato and Cucumber',
ingredients : 'bagels, cream cheese, small Kirby cucumber,plum tomato'
}
];
let Recipe = Backbone.Model.extend({
defaults : {
title : 'Empty receipe record',
ingredients : 'sugar, milk ...'
}
});
let Recipes = Backbone.Collection.extend({
initialize() {
this.fetch();
if (this.models.length === 0) {
FIXTURES.map((f) => this.add(f).save());
}
},
model : Recipe,
localStorage: new Backbone.LocalStorage("_username_recipes")
});
let Router = Backbone.Router.extend({
routes : {
'' : 'index',
'show/:id' : 'show',
'add' : 'add'
},
index() {
this.state = 'index';
},
show(id) {
this.state = 'show';
this.stateID = id;
},
add() {
this.state = 'add';
}
});
class RecipesIndex extends React.Component {
go(link) {
this.props.router.navigate(link)
}
render() {
let items = this.props.recipes.models.map((r) => {
let link = '#/show/' + r.get('id');
let ingredients = r.get('ingredients').split(',').map((i) => {
return <span className="label label-default"><i className="fa fa-tint"></i>
{i}</span>
});
return (
<li onClick={this.go.bind(this, link)} className="list-group-item">
<h4><i className="fa fa-star-o"></i>
{r.get('title')}</h4>
{ingredients}
</li>
)
});
return (
<ul className="list-group">
{items}
</ul>
)
}
}
class RecipeShow extends React.Component {
onSave() {
let title = document.getElementById('recipe-title').value;
let ingredients = document.getElementById('recipe-ingredients').value;
if (title.length > 0 && ingredients.length > 0) {
this.props.recipe.set('title', title);
this.props.recipe.set('ingredients', ingredients);
this.props.recipe.save();
this.props.router.navigate('#/');
}
}
onRemove() {
this.props.recipe.destroy();
this.props.router.navigate('#/');
}
render() {
return (
<div className="recipe-editor">
<h3>Recipe title:</h3>
<input type="text" id="recipe-title" className="form-control input-lg" defaultValue={this.props.recipe.get('title')} autofocus />
<h3>Ingredients:</h3>
<textarea type="text" id="recipe-ingredients" className="form-control input-lg" defaultValue={this.props.recipe.get('ingredients')} />
<p>
<span onClick={this.onSave.bind(this)} className="btn btn-info btn-lg input-lg form-control"><i className="fa fa-floppy-o"></i> Save</span>
<span onClick={this.onRemove.bind(this)}className="btn btn-danger btn-lg input-lg form-control"><i className="fa fa-times"></i> Remove</span>
</p>
</div>
)
}
}
class RecipeAdd extends React.Component {
onCreate() {
let title = document.getElementById('recipe-title').value;
let ingredients = document.getElementById('recipe-ingredients').value;
if (title.length > 0 && ingredients.length > 0) {
this.props.recipes.add(
{'title': title, 'ingredients': ingredients }).save();
this.props.router.navigate('#/');
}
}
render() {
return (
<div className="recipe-editor">
<h3>Recipe title:</h3>
<input type="text" id="recipe-title" className="form-control input-lg" placeholder="Recipe title ..." autofocus />
<h3>Ingredients:</h3>
<textarea type="text" id="recipe-ingredients" className="form-control input-lg" placeholder="Ingredients ..." />
<p>
<span onClick={this.onCreate.bind(this)} className="btn btn-info btn-lg input-lg form-control"><i className="fa fa-plus"></i>
Create</span>
</p>
</div>
)
}
}
class ReceipesDispatcher extends React.Component {
constructor(props) {
super(props);
this.callback = this.onRoute.bind(this);
this.state = {
route : 'index',
id : ''
};
}
onRoute() {
this.setState({
route : this.props.router.state,
id : this.props.router.stateID
})
}
componentWillUnmount() {
this.props.router.off('route', this.callback);
}
componentDidMount() {
this.props.router.on('route', this.callback);
}
render() {
let box = <RecipesIndex recipes={this.props.recipes} router={this.props.router} />
let showAdd = true;
if (this.state.route === 'show') {
var recipe = this.props.recipes.get(this.state.id);
box = <RecipeShow recipe={recipe} router={this.props.router} />
showAdd = false;
}
if (this.state.route === 'add') {
box = <RecipeAdd recipes={this.props.recipes} router={this.props.router} />
showAdd = false;
}
return (
<div className="container-wrapper">
<div className="container">
<h2 className="container-title"><i className="fa fa-bookmark"></i>
<a href="#/">Recipe Box</a>{ showAdd === true ?
<a className="pull-right btn" href="#/add">Create Recipe <i className="fa fa-plus"></i>
</a>
: <p></p> }</h2>
{box}
</div>
</div>
)
}
}
let recipes = new Recipes();
let router = new Router();
React.render(<ReceipesDispatcher router={router} recipes={recipes} />, document.body);
Backbone.history.start();
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.4/zepto.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.1.16/backbone.localStorage-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.min.js"></script>
body,html
font-family: 'Roboto', sans-serif
height: 100%
.container-wrapper
display: flex
margin: auto
height: 100%
.container
background: #924da3
overflow: hidden
margin: auto
border-radius: 5px
padding: 0px
box-shadow: 0px 1px 10px #000
h2.container-title
position: relative
background: #624da3
margin: 0px
color: #fff
a
color: #fff
font-weight: bold
text-transform: uppercase
i.fa-bookmark
margin-right: 10px
h2
padding: 30px 45px
.list-group
border-radius: 0px
margin: 0px
position: relative
li:first-child
border-top-left-radius: 0px
border-top-right-radius: 0px
li
position: relative
border-radius: 0px
border: none
padding: 10px
margin: 0px
background: #824da3
cursor: pointer
transition: all 0.2s ease
li:nth-child(even)
background: #924da3
li:hover,li:focus
top: 0px
transition: all 0.2s ease
padding-bottom: 20px
margin-top: -10px
.label
background: #624da3
margin: 0px 5px
font-size: 14px
i
margin-right: 5px
h4
padding: 10px
color: #fff
font-size: 24px
line-height: 42px
i
font-size: 38px
margin-right: 10px
.recipe-editor
padding: 20px
color: #fff
.btn
i
margin-right: 10px
margin-top: -20px
.btn-info
background: #624da3
border: 0px
text-transform: uppercase
padding: 30px
line-height: 0px
.btn-info:hover,.bth-info:focus
background: #324da3
.btn-danger
padding: 30px
line-height: 0px
text-transform: uppercase
p
margin: 10px 0px
span
margin: 5px 0px
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment