A Pen by Svetlana Linuxenko on CodePen.
Created
March 25, 2016 18:25
-
-
Save linuxenko/ab2fa9dc55d554b52a43 to your computer and use it in GitHub Desktop.
Build a Recipe Box [freeCodeCamp [Data Visualization]] (Challenge)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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