├── catch-of-the-day
├── .eslintrc.json
├── .gitignore
├── build
│ └── favicon.ico
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── security-rules.json
└── src
│ ├── base.js
│ ├── components
│ ├── .gitkeep
│ ├── AddFishForm.js
│ ├── App.js
│ ├── Fish.js
│ ├── Header.js
│ ├── Inventory.js
│ ├── NotFound.js
│ ├── Order.js
│ └── StorePicker.js
│ ├── css
│ ├── _animations-finished.styl
│ ├── _animations.styl
│ ├── _colours.styl
│ ├── _fonts.styl
│ ├── _normalize.styl
│ ├── _typography.styl
│ ├── fonts
│ │ ├── blanch_caps_inline-webfont.eot
│ │ ├── blanch_caps_inline-webfont.svg
│ │ ├── blanch_caps_inline-webfont.ttf
│ │ ├── blanch_caps_inline-webfont.woff
│ │ ├── haymaker-webfont.eot
│ │ ├── haymaker-webfont.svg
│ │ ├── haymaker-webfont.ttf
│ │ └── haymaker-webfont.woff
│ ├── images
│ │ └── anchor.svg
│ ├── style.css
│ └── style.styl
│ ├── helpers.js
│ ├── index.js
│ └── sample-fishes.js
└── readme.md
/catch-of-the-day/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true,
6 | "node": true
7 | },
8 | "extends": "eslint:recommended",
9 | "parserOptions": {
10 | "ecmaFeatures": {
11 | "experimentalObjectRestSpread": true,
12 | "jsx": true
13 | },
14 | "sourceType": "module"
15 | },
16 | "plugins": [
17 | "react"
18 | ],
19 | "rules": {
20 | "indent": [
21 | "error",
22 | "tab"
23 | ],
24 | "linebreak-style": [
25 | 0
26 | ],
27 | "quotes": [
28 | 0
29 | ],
30 | "semi": [
31 | 0
32 | ],
33 | "no-unused-vars": [0],
34 | "no-console": [0]
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/catch-of-the-day/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | *.zip
3 | .DS_Store
4 | npm-debug.log
5 | stepped-solutions/
6 | notes.txt
7 |
--------------------------------------------------------------------------------
/catch-of-the-day/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/build/favicon.ico
--------------------------------------------------------------------------------
/catch-of-the-day/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cotd",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "autoprefixer-stylus": "0.10.0",
7 | "concurrently": "3.0.0",
8 | "react-scripts": "0.6.0",
9 | "stylus": "^0.54.5"
10 | },
11 | "dependencies": {
12 | "history": "4.2.0",
13 | "re-base": "2.2.0",
14 | "react": "15.3.2",
15 | "react-addons-css-transition-group": "15.3.2",
16 | "react-dom": "15.3.2",
17 | "react-router": "4.0.0-alpha.3"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "watch": "concurrently --names 'webpack, stylus' --prefix name 'npm run start' 'npm run styles:watch'",
22 | "build": "react-scripts build",
23 | "eject": "react-scripts eject",
24 | "styles": "stylus -u autoprefixer-stylus ./src/css/style.styl -o ./src/css/style.css",
25 | "styles:watch": "stylus -u autoprefixer-stylus -w ./src/css/style.styl -o ./src/css/style.css",
26 | "deploy": "ns ./build --cmd 'list ./content -s'"
27 | },
28 | "eslintConfig": {
29 | "extends": "./node_modules/react-scripts/config/eslint.js"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/catch-of-the-day/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/public/favicon.ico
--------------------------------------------------------------------------------
/catch-of-the-day/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Catch of the Day
7 |
8 |
9 |
10 | Fold
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/catch-of-the-day/security-rules.json:
--------------------------------------------------------------------------------
1 | // These are your firebase security rules - put them in the "Security & Rules" tab of your database
2 | {
3 | "rules": {
4 | // won't let people delete an existing room
5 | ".write": "!data.exists()",
6 | ".read": true,
7 | "$room" : {
8 | // only the store owner can edit the data
9 | ".write" : "newData.child('owner').val() === auth.uid",
10 | ".read" : true
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/base.js:
--------------------------------------------------------------------------------
1 | import Rebase from 're-base';
2 |
3 | const base = Rebase.createClass({
4 | apiKey: "AIzaSyAmBH7Ih3ZsyPOhk8PFekHIShaXRK4RfCM",
5 | authDomain: "catch-of-the-day-maria-dc.firebaseapp.com",
6 | databaseURL: "https://catch-of-the-day-maria-dc.firebaseio.com",
7 | });
8 |
9 | export default base;
10 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/.gitkeep:
--------------------------------------------------------------------------------
1 | // this is just an empty file so the empty folder will stay in git!
2 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/AddFishForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class AddFishForm extends React.Component {
4 | createFish(event) {
5 | event.preventDefault();
6 | console.log('Gonna make some fish!');
7 | const fish = {
8 | name: this.name.value,
9 | price: this.price.value,
10 | status: this.status.value,
11 | desc: this.desc.value,
12 | image: this.image.value,
13 | }
14 | this.props.addFish(fish);
15 | this.fishForm.reset();
16 | }
17 | render() {
18 | return (
19 |
30 | )
31 | }
32 | }
33 |
34 | AddFishForm.propTypes = {
35 | addFish: React.PropTypes.func.isRequired
36 | }
37 |
38 | export default AddFishForm;
39 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Header from './Header';
3 | import Order from './Order';
4 | import Inventory from './Inventory';
5 | import Fish from './Fish';
6 | import sampleFishes from '../sample-fishes';
7 | import base from '../base';
8 |
9 | class App extends React.Component {
10 | constructor() {
11 | super();
12 | this.addFish = this.addFish.bind(this);
13 | this.removeFromOrder.bind(this);
14 | this.removeFish = this.removeFish.bind(this);
15 | this.updateFish = this.updateFish.bind(this);
16 | this.loadSamples = this.loadSamples.bind(this);
17 | this.addToOrder = this.addToOrder.bind(this);
18 | this.removeFromOrder = this.removeFromOrder.bind(this);
19 | // initial state (getInitialState if you are using reactCreateClass as we are here)
20 | this.state = {
21 | fishes: {},
22 | order: {}
23 | };
24 |
25 | }
26 |
27 | componentWillMount() {
28 | // this runs right before is rendered
29 | this.ref = base.syncState(`${this.props.params.storeId}/fishes`, {
30 | context: this,
31 | state: 'fishes'
32 | });
33 | // check if there is any order in local storage
34 | const localStorageRef = localStorage.getItem(`order-${this.props.params.storeId}`);
35 | if(localStorageRef) {
36 | // update our App Component's order state
37 | this.setState({
38 | // changes string back to object
39 | order: JSON.parse(localStorageRef)
40 | });
41 | }
42 | }
43 |
44 | componentWillUnMount() {
45 | base.removeBinding(this.ref);
46 | }
47 |
48 | componentWillUpdate(nextProps, nextState) {
49 | localStorage.setItem(`order-${this.props.params.storeId}`, JSON.stringify(nextState.order));
50 | }
51 |
52 | addFish(fish) {
53 | // update our state
54 | const fishes = {...this.state.fishes};
55 | // set state. Date.now() gives timestamp. New to JS.
56 | const timestamp = Date.now();
57 | fishes[`fish-${timestamp}`] = fish;
58 | // set state passing only the object that has changed here.
59 | this.setState({ fishes });
60 | }
61 |
62 | updateFish(key, updatedFish) {
63 | const fishes = {...this.state.fishes};
64 | fishes[key] = updatedFish;
65 | this.setState({ fishes });
66 | }
67 |
68 | removeFish(key) {
69 | const fishes = {...this.state.fishes};
70 | fishes[key] = null;
71 | this.setState({ fishes });
72 | }
73 |
74 | loadSamples() {
75 | this.setState({
76 | fishes: sampleFishes
77 | });
78 | }
79 |
80 | addToOrder(key) {
81 | // take a copy of our state
82 | const order = {...this.state.order};
83 | // update or add new number of fish ordered
84 | order[key] = order[key] + 1 || 1;
85 | // update our state (or ({ order: order }))
86 | this.setState({ order });
87 |
88 | }
89 |
90 | removeFromOrder(key) {
91 | const order = {...this.state.order};
92 | delete order[key];
93 | this.setState({ order });
94 | }
95 |
96 | render() {
97 | return (
98 |
99 |
100 |
101 |
102 | {
103 | Object
104 | .keys(this.state.fishes)
105 | .map(key => )
106 | }
107 |
108 |
109 |
110 |
112 |
113 | )
114 | }
115 | }
116 |
117 | App.propTypes = {
118 | params: React.PropTypes.object.isRequired
119 | }
120 |
121 | export default App;
122 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/Fish.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { formatPrice } from '../helpers';
3 |
4 | class Fish extends React.Component {
5 | render() {
6 | const { details, index } = this.props;
7 | const isAvailable = details.status === 'available';
8 | const buttonText = isAvailable ? 'Add To Order' : 'Sold Out';
9 | return (
10 |
11 |
12 |
13 | {details.name}
14 | {formatPrice(details.price)}
15 |
16 | {details.desc}
17 | this.props.addToOrder(index)} disabled={!isAvailable}>{buttonText}
18 |
19 | )
20 | }
21 | }
22 |
23 | Fish.propTypes = {
24 | details: React.PropTypes.object.isRequired,
25 | index: React.PropTypes.string.isRequired,
26 | addToOrder: React.PropTypes.func.isRequired
27 | }
28 |
29 | export default Fish;
30 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Header = (props) => {
4 | return (
5 |
6 |
7 | Catch
8 |
9 | of
10 | the
11 |
12 | Day
13 |
14 |
15 | {props.tagline}
16 |
17 |
18 | )
19 | }
20 |
21 | Header.propTypes = {
22 | tagline: React.PropTypes.string.isRequired
23 | }
24 |
25 | export default Header;
26 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/Inventory.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddFishForm from './AddFishForm';
3 | import base from '../base';
4 |
5 | class Inventory extends React.Component {
6 | constructor() {
7 | super();
8 | this.renderInventory = this.renderInventory.bind(this);
9 | this.renderLogin = this.renderLogin.bind(this);
10 | this.renderLogin = this.renderLogin.bind(this);
11 | this.authenticate = this.authenticate.bind(this);
12 | this.logout = this.logout.bind(this);
13 | this.authHandler = this.authHandler.bind(this);
14 | this.handleChange = this.handleChange.bind(this);
15 | this.state = {
16 | uid: null,
17 | owner: null
18 | }
19 | }
20 |
21 | componentDidMount() {
22 | base.onAuth((user) => {
23 | if(user) {
24 | this.authHandler(null, { user });
25 | }
26 | });
27 | }
28 |
29 | handleChange(e, key) {
30 | const fish = this.props.fishes[key];
31 | // take copy of fish and update it with new data
32 | const updatedFish = {
33 | ...fish,
34 | [e.target.name]: e.target.value
35 | }
36 | this.props.updateFish(key, updatedFish);
37 | }
38 |
39 | authenticate(provider) {
40 | console.log(`Trying to log in with ${provider}`);
41 | base.authWithOAuthPopup(provider, this.authHandler);
42 | }
43 |
44 | logout() {
45 | base.unauth();
46 | this.setState({
47 | uid: null
48 | });
49 | }
50 |
51 | authHandler(err, authData) {
52 | console.log(authData);
53 | if(err) {
54 | console.error(err);
55 | return;
56 | }
57 |
58 | // grab store info if the current user is owner
59 | const storeRef = base.database().ref(this.props.storeId);
60 | // query firebase data once for store data
61 | storeRef.once('value', (snapshot) => {
62 | const data = snapshot.val() || {};
63 |
64 | // claim as our own if no owner already
65 | if(!data.owner) {
66 | storeRef.set({
67 | owner: authData.user.uid
68 | });
69 | }
70 |
71 | this.setState({
72 | uid: authData.user.uid,
73 | owner: data.owner || authData.user.uid
74 | });
75 | });
76 |
77 | }
78 |
79 | renderLogin() {
80 | return (
81 |
82 | Inventory
83 | Sign in to manage your store's inventory
84 | this.authenticate('github')}>Login with Github
85 | this.authenticate('facebook')}>Login with Facebook
86 |
87 | )
88 | }
89 |
90 | renderInventory(key) {
91 | const fish = this.props.fishes[key];
92 | return (
93 |
94 | this.handleChange(e, key)} />
95 | this.handleChange(e, key)} />
96 | this.handleChange(e, key)}>
97 | Fresh!
98 | Sold Out!
99 |
100 | this.handleChange(e, key)}>
101 | this.handleChange(e, key)} />
102 | this.props.removeFish(key)}>Remove Fish
103 |
104 | )
105 | }
106 | render() {
107 | const logout = Log Out ;
108 | // check if anyone is logged in (really not logged in at all)
109 | if(!this.state.uid) {
110 | return {this.renderLogin()}
111 | }
112 | // check if current user is owner of current store
113 | if(this.state.uid !== this.state.owner) {
114 | return (
115 |
116 |
Sorry, you aren't the owner of this store!
117 | {logout}
118 |
119 | )
120 | }
121 | return (
122 |
123 |
Inventory
124 | {logout}
125 | {Object.keys(this.props.fishes).map(this.renderInventory)}
126 |
127 | Load Sample Fishes
128 |
129 |
130 | )
131 | }
132 | }
133 |
134 | Inventory.propTypes = {
135 | fishes: React.PropTypes.object.isRequired,
136 | updateFish: React.PropTypes.func.isRequired,
137 | removeFish: React.PropTypes.func.isRequired,
138 | addFish: React.PropTypes.func.isRequired,
139 | loadSamples: React.PropTypes.func.isRequired,
140 | storeId: React.PropTypes.string.isRequired
141 | }
142 |
143 | export default Inventory;
144 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class NotFound extends React.Component {
4 | render() {
5 | return (
6 | Not Found!111!!
7 | )
8 | }
9 | }
10 |
11 | export default NotFound;
12 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/Order.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { formatPrice } from '../helpers';
3 | import CSSTransitionGroup from 'react-addons-css-transition-group';
4 |
5 | class Order extends React.Component {
6 | constructor() {
7 | super();
8 | this.renderOrder = this.renderOrder.bind(this);
9 | }
10 | renderOrder(key) {
11 | const fish = this.props.fishes[key];
12 | const count = this.props.order[key];
13 | const removeButton = this.props.removeFromOrder(key)}>×
14 |
15 | if(!fish || fish.status === 'unavailable') {
16 | return Sorry, {fish ? fish.name : 'fish'} is no longer available!{removeButton}
17 | }
18 |
19 | return (
20 |
21 |
22 |
23 | {count}
24 |
25 | lbs {fish.name} {removeButton}
26 |
27 | {formatPrice(count * fish.price)}
28 |
29 | )
30 | }
31 | render() {
32 | const orderIds = Object.keys(this.props.order);
33 | const total = orderIds.reduce((prevTotal, key) => {
34 | // because all fishes and not current/specific fish
35 | const fish = this.props.fishes[key];
36 | // need count - how many bought
37 | const count = this.props.order[key];
38 | // because things can change at any given moment. real time app
39 | const isAvailable = fish && fish.status === 'available';
40 | // add it up
41 | if(isAvailable) {
42 | // || 0 because sometimes the fish will be in order but subsequently deleted
43 | return prevTotal + (count * fish.price || 0)
44 | }
45 | // otherwise last amount
46 | return prevTotal;
47 | // need to start with starting value
48 | }, 0);
49 | return (
50 |
51 |
Your Order
52 |
53 | {orderIds.map(this.renderOrder)}
54 |
55 | Total:
56 | {formatPrice(total)}
57 |
58 |
59 |
60 | )
61 | }
62 | }
63 |
64 | Order.propTypes = {
65 | fishes: React.PropTypes.object.isRequired,
66 | order: React.PropTypes.object.isRequired,
67 | removeFromOrder: React.PropTypes.func.isRequired
68 | }
69 |
70 | export default Order;
71 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/components/StorePicker.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { getFunName } from '../helpers';
3 |
4 | class StorePicker extends React.Component {
5 | // every component you build needs at least one method and that's the render method
6 | goToStore(event) {
7 | // prevents page refresh
8 | event.preventDefault();
9 | console.log('You changed the URL');
10 | // first grab text from box
11 | const storeId = this.storeInput.value;
12 | console.log(`Going to ${storeId}`)
13 | // second transition from / to /store/storeId
14 | this.context.router.transitionTo(`/store/${storeId}`);
15 | }
16 | render() {
17 | // Anywhere else
18 | return (
19 | this.goToStore(e)}>
20 | Please Enter A Store
21 | { this.storeInput = input}} />
22 | Visit Store →
23 |
24 | )
25 | }
26 | }
27 |
28 | // surface router. tell React that StorePicker component expects something called a router, and router says ok, I will make this router available to you.
29 | StorePicker.contextTypes = {
30 | router: React.PropTypes.object
31 | }
32 |
33 | export default StorePicker;
34 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_animations-finished.styl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/_animations-finished.styl
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_animations.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Possible Animations:
3 | enter
4 | leave
5 | appear Must set transitionAppear={true} on animation component
6 | */
7 |
8 | .order-enter
9 | max-height 0
10 | transition all 0.5s
11 | transform: translateX(-120%)
12 |
13 | &.order-enter-active
14 | max-height 60px
15 | padding 2rem 0 !important
16 | transform: translateX(0)
17 |
18 | .order-leave
19 | transition all 0.5s
20 | transform translateX(0)
21 | &.order-leave-active
22 | transform translateX(120%)
23 | max-height: 0
24 | padding: 0
25 |
26 | .count-enter
27 | transition all .5s
28 | // start offscreen
29 | transform translateY(100%)
30 | &.count-enter-active
31 | // back to normal
32 | transform translateY(0)
33 |
34 | .count-leave
35 | transition all .5s
36 | // because need one number to overlap other
37 | position absolute
38 | left 0
39 | bottom 0
40 | // starting from where it is
41 | transform translateY(0)
42 | &.count-leave-active
43 | transform translateY(-100%)
44 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_colours.styl:
--------------------------------------------------------------------------------
1 | orange = #F5A623
2 | red = #d12028
3 | green = #2DC22D
4 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_fonts.styl:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "haymakerregular";
3 | src: url("./fonts/haymaker-webfont.eot");
4 | src: url("./fonts/haymaker-webfont.eot?#iefix") format("embedded-opentype"), url("./fonts/haymaker-webfont.woff") format("woff"), url("./fonts/haymaker-webfont.ttf") format("truetype"), url("./fonts/haymaker-webfont.svg#haymakerregular") format("svg");
5 | font-weight: normal;
6 | font-style: normal;
7 | }
8 |
9 | @font-face {
10 | font-family: 'blanchcaps_inline';
11 | src: url('./fonts/blanch_caps_inline-webfont.eot');
12 | src: url('./fonts/blanch_caps_inline-webfont.eot?#iefix') format('embedded-opentype'),
13 | url('./fonts/blanch_caps_inline-webfont.woff') format('woff'),
14 | url('./fonts/blanch_caps_inline-webfont.ttf') format('truetype'),
15 | url('./fonts/blanch_caps_inline-webfont.svg#blanchcaps_inline') format('svg');
16 | font-weight: normal;
17 | font-style: normal;
18 | }
19 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_normalize.styl:
--------------------------------------------------------------------------------
1 | // CSS Normalize
2 |
3 | article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block;}audio,canvas,video{display:inline-block;}audio:not([controls]){display:none;height:0;}[hidden]{display:none;}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}a:focus{outline:thin dotted;}a:active,a:hover{outline:0;}h1{font-size:2em;}abbr[title]{border-bottom:1px dotted;}b,strong{font-weight:700;}dfn{font-style:italic;}mark{background:#ff0;color:#000;}code,kbd,pre,samp{font-family:monospace, serif;font-size:1em;}pre{white-space:pre-wrap;word-wrap:break-word;}q{quotes:\201C \201D \2018 \2019;}small{font-size:80%;}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}sup{top:-.5em;}sub{bottom:-.25em;}img{border:0;}svg:not(:root){overflow:hidden;}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em;}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0;}button,input{line-height:normal;}button,html input[type=button], input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;}button[disabled],input[disabled]{cursor:default;}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none;}textarea{overflow:auto;vertical-align:top;}table{border-collapse:collapse;border-spacing:0;}body,figure{margin:0;}legend,button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
4 |
5 | // clearfix
6 | .clearfix:after {visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }
7 |
8 | // Sane border box
9 | * { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
10 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/_typography.styl:
--------------------------------------------------------------------------------
1 | html
2 | font-size 62.5%
3 |
4 | body
5 | background #D4D4D4
6 | -webkit-font-smoothing antialiased
7 | -moz-osx-font-smoothing grayscale
8 | font-family 'Open Sans', sans-serif
9 | font-size 2rem
10 |
11 | h1
12 | font-family 'blanchcaps_inline', sans-serif;
13 | text-align center
14 | font-weight normal
15 | margin 0
16 |
17 | h2,h3,h4,h5,h6
18 | font-weight normal
19 | font-family 'haymakerregular', sans-serif
20 |
21 | h2
22 | text-align center
23 | margin-top 0
24 | margin-bottom 2rem
25 |
26 | h3
27 | font-size 3rem
28 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.eot
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.ttf
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/blanch_caps_inline-webfont.woff
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/haymaker-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/haymaker-webfont.eot
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/haymaker-webfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/haymaker-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/haymaker-webfont.ttf
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/fonts/haymaker-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gaearon/react-for-beginners/d1fad715855fb2a02e02b93e7da8ccac01a41484/catch-of-the-day/src/css/fonts/haymaker-webfont.woff
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/images/anchor.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/style.css:
--------------------------------------------------------------------------------
1 | .order-enter {
2 | -webkit-transition: all 0.5s;
3 | transition: all 0.5s;
4 | }
5 | transform: translateX(-120%) {
6 | max-height: 0;
7 | }
8 | transform: translateX(-120%).order-enter-active {
9 | max-height: 60px;
10 | padding: 2rem 0 !important;
11 | -webkit-transform: translateX(0);
12 | transform: translateX(0);
13 | }
14 | .order-leave {
15 | -webkit-transition: all 0.5s;
16 | transition: all 0.5s;
17 | -webkit-transform: translateX(0);
18 | transform: translateX(0);
19 | }
20 | .order-leave.order-leave-active {
21 | -webkit-transform: translateX(120%);
22 | transform: translateX(120%);
23 | max-height: 0;
24 | padding: 0;
25 | }
26 | .count-enter {
27 | -webkit-transition: all 0.5s;
28 | transition: all 0.5s;
29 | -webkit-transform: translateY(100%);
30 | transform: translateY(100%);
31 | }
32 | .count-enter.count-enter-active {
33 | -webkit-transform: translateY(0);
34 | transform: translateY(0);
35 | }
36 | .count-leave {
37 | -webkit-transition: all 0.5s;
38 | transition: all 0.5s;
39 | position: absolute;
40 | left: 0;
41 | bottom: 0;
42 | -webkit-transform: translateY(0);
43 | transform: translateY(0);
44 | }
45 | .count-leave.count-leave-active {
46 | -webkit-transform: translateY(-100%);
47 | transform: translateY(-100%);
48 | }
49 | @font-face {
50 | font-family: "haymakerregular";
51 | src: url("./fonts/haymaker-webfont.eot");
52 | src: url("./fonts/haymaker-webfont.eot?#iefix") format("embedded-opentype"), url("./fonts/haymaker-webfont.woff") format("woff"), url("./fonts/haymaker-webfont.ttf") format("truetype"), url("./fonts/haymaker-webfont.svg#haymakerregular") format("svg");
53 | font-weight: normal;
54 | font-style: normal;
55 | }
56 | @font-face {
57 | font-family: 'blanchcaps_inline';
58 | src: url("./fonts/blanch_caps_inline-webfont.eot");
59 | src: url("./fonts/blanch_caps_inline-webfont.eot?#iefix") format('embedded-opentype'), url("./fonts/blanch_caps_inline-webfont.woff") format('woff'), url("./fonts/blanch_caps_inline-webfont.ttf") format('truetype'), url("./fonts/blanch_caps_inline-webfont.svg#blanchcaps_inline") format('svg');
60 | font-weight: normal;
61 | font-style: normal;
62 | }
63 | article,
64 | aside,
65 | details,
66 | figcaption,
67 | figure,
68 | footer,
69 | header,
70 | hgroup,
71 | nav,
72 | section,
73 | summary {
74 | display: block;
75 | }
76 | audio,
77 | canvas,
78 | video {
79 | display: inline-block;
80 | }
81 | audio:not([controls]) {
82 | display: none;
83 | height: 0;
84 | }
85 | [hidden] {
86 | display: none;
87 | }
88 | html {
89 | font-family: sans-serif;
90 | -webkit-text-size-adjust: 100%;
91 | -ms-text-size-adjust: 100%;
92 | }
93 | a:focus {
94 | outline: thin dotted;
95 | }
96 | a:active,
97 | a:hover {
98 | outline: 0;
99 | }
100 | h1 {
101 | font-size: 2em;
102 | }
103 | abbr[title] {
104 | border-bottom: 1px dotted;
105 | }
106 | b,
107 | strong {
108 | font-weight: 700;
109 | }
110 | dfn {
111 | font-style: italic;
112 | }
113 | mark {
114 | background: #ff0;
115 | color: #000;
116 | }
117 | code,
118 | kbd,
119 | pre,
120 | samp {
121 | font-family: monospace, serif;
122 | font-size: 1em;
123 | }
124 | pre {
125 | white-space: pre-wrap;
126 | word-wrap: break-word;
127 | }
128 | q {
129 | quotes: 2 1C 2 1D 2 18 2 19;
130 | }
131 | small {
132 | font-size: 80%;
133 | }
134 | sub,
135 | sup {
136 | font-size: 75%;
137 | line-height: 0;
138 | position: relative;
139 | vertical-align: baseline;
140 | }
141 | sup {
142 | top: -0.5em;
143 | }
144 | sub {
145 | bottom: -0.25em;
146 | }
147 | img {
148 | border: 0;
149 | }
150 | svg:not(:root) {
151 | overflow: hidden;
152 | }
153 | fieldset {
154 | border: 1px solid #c0c0c0;
155 | margin: 0 2px;
156 | padding: 0.35em 0.625em 0.75em;
157 | }
158 | button,
159 | input,
160 | select,
161 | textarea {
162 | font-family: inherit;
163 | font-size: 100%;
164 | margin: 0;
165 | }
166 | button,
167 | input {
168 | line-height: normal;
169 | }
170 | button,
171 | html input[type=button],
172 | input[type=reset],
173 | input[type=submit] {
174 | -webkit-appearance: button;
175 | cursor: pointer;
176 | }
177 | button[disabled],
178 | input[disabled] {
179 | cursor: default;
180 | }
181 | input[type=checkbox],
182 | input[type=radio] {
183 | box-sizing: border-box;
184 | padding: 0;
185 | }
186 | input[type=search] {
187 | -webkit-appearance: textfield;
188 | box-sizing: content-box;
189 | }
190 | input[type=search]::-webkit-search-cancel-button,
191 | input[type=search]::-webkit-search-decoration {
192 | -webkit-appearance: none;
193 | }
194 | textarea {
195 | overflow: auto;
196 | vertical-align: top;
197 | }
198 | table {
199 | border-collapse: collapse;
200 | border-spacing: 0;
201 | }
202 | body,
203 | figure {
204 | margin: 0;
205 | }
206 | legend,
207 | button::-moz-focus-inner,
208 | input::-moz-focus-inner {
209 | border: 0;
210 | padding: 0;
211 | }
212 | .clearfix:after {
213 | visibility: hidden;
214 | display: block;
215 | font-size: 0;
216 | content: " ";
217 | clear: both;
218 | height: 0;
219 | }
220 | * {
221 | box-sizing: border-box;
222 | }
223 | html {
224 | font-size: 62.5%;
225 | }
226 | body {
227 | background: #d4d4d4;
228 | -webkit-font-smoothing: antialiased;
229 | -moz-osx-font-smoothing: grayscale;
230 | font-family: 'Open Sans', sans-serif;
231 | font-size: 2rem;
232 | }
233 | h1 {
234 | font-family: 'blanchcaps_inline', sans-serif;
235 | text-align: center;
236 | font-weight: normal;
237 | margin: 0;
238 | }
239 | h2,
240 | h3,
241 | h4,
242 | h5,
243 | h6 {
244 | font-weight: normal;
245 | font-family: 'haymakerregular', sans-serif;
246 | }
247 | h2 {
248 | text-align: center;
249 | margin-top: 0;
250 | margin-bottom: 2rem;
251 | }
252 | h3 {
253 | font-size: 3rem;
254 | }
255 | header.top {
256 | text-align: center;
257 | }
258 | header.top h1 {
259 | font-size: 14.4rem;
260 | line-height: 0.7;
261 | display: -webkit-box;
262 | display: -ms-flexbox;
263 | display: flex;
264 | -webkit-box-pack: center;
265 | -ms-flex-pack: center;
266 | justify-content: center;
267 | }
268 | header.top h1 .ofThe {
269 | display: -webkit-box;
270 | display: -ms-flexbox;
271 | display: flex;
272 | font-size: 3rem;
273 | color: #f5a623;
274 | -webkit-box-pack: center;
275 | -ms-flex-pack: center;
276 | justify-content: center;
277 | -webkit-box-align: center;
278 | -ms-flex-align: center;
279 | align-items: center;
280 | background: url("images/anchor.svg") center no-repeat;
281 | background-size: cover;
282 | padding: 0 1rem;
283 | }
284 | header.top h1 .ofThe .of {
285 | padding-right: 2rem;
286 | position: relative;
287 | right: -0.5rem;
288 | }
289 | header.top h3 {
290 | margin: 0;
291 | font-size: 2rem;
292 | color: #f5a623;
293 | position: relative;
294 | display: inline-block;
295 | }
296 | header.top h3 span {
297 | background: #fff;
298 | position: relative;
299 | z-index: 2;
300 | padding-left: 1rem;
301 | padding-right: 1rem;
302 | }
303 | header.top h3:before,
304 | header.top h3:after {
305 | display: block;
306 | z-index: 1;
307 | background: #000;
308 | position: absolute;
309 | width: 130%;
310 | height: 1px;
311 | content: '';
312 | top: 5px;
313 | margin-left: -15%;
314 | }
315 | header.top h3:after {
316 | top: auto;
317 | bottom: 7px;
318 | }
319 | .catch-of-the-day {
320 | display: -webkit-box;
321 | display: -ms-flexbox;
322 | display: flex;
323 | height: 90vh;
324 | max-width: 1500px;
325 | margin: 0 auto;
326 | margin-top: 5vh;
327 | -webkit-perspective: 1000;
328 | perspective: 1000;
329 | -webkit-transform-style: preserve-3d;
330 | transform-style: preserve-3d;
331 | }
332 | .catch-of-the-day > * {
333 | -webkit-box-flex: 1;
334 | -ms-flex: 1 4 auto;
335 | flex: 1 4 auto;
336 | padding: 2rem;
337 | border: 1rem double #1a1a1a;
338 | position: relative;
339 | background: #fff;
340 | -webkit-transition: all 0.3s;
341 | transition: all 0.3s;
342 | box-shadow: 0px 5px 5px rgba(0,0,0,0.1);
343 | overflow: scroll;
344 | }
345 | .catch-of-the-day > *:first-child {
346 | -ms-flex-negative: 1;
347 | flex-shrink: 1;
348 | -ms-flex-preferred-size: 50%;
349 | flex-basis: 50%;
350 | -webkit-transform: translateX(50%) rotateY(6deg) translateX(-50%);
351 | transform: translateX(50%) rotateY(6deg) translateX(-50%);
352 | }
353 | .catch-of-the-day > *:nth-child(2) {
354 | -webkit-transform: translateX(-50%) rotateY(-14deg) translateX(50%);
355 | transform: translateX(-50%) rotateY(-14deg) translateX(50%);
356 | border-left: 0;
357 | border-right: 0;
358 | min-width: 300px;
359 | }
360 | .catch-of-the-day > *:last-child {
361 | -ms-flex-negative: 1;
362 | flex-shrink: 1;
363 | -ms-flex-preferred-size: 50%;
364 | flex-basis: 50%;
365 | -webkit-transform: translateX(-50%) rotateY(10deg) translateX(50%) scale(1.08) translateX(24px);
366 | transform: translateX(-50%) rotateY(10deg) translateX(50%) scale(1.08) translateX(24px);
367 | }
368 | input#fold:not(:checked) ~ #main .catch-of-the-day > * {
369 | -webkit-transform: none;
370 | transform: none;
371 | }
372 | label[for="fold"] {
373 | position: absolute;
374 | top: 1rem;
375 | left: 1rem;
376 | text-transform: uppercase;
377 | font-size: 1.3rem;
378 | background: #000;
379 | color: #fff;
380 | border: 2px solid #000;
381 | cursor: pointer;
382 | padding: 0.5rem 1rem;
383 | }
384 | input#fold {
385 | display: none;
386 | }
387 | input#fold:checked + label {
388 | background: #fff;
389 | color: #000;
390 | }
391 | ul {
392 | list-style: none;
393 | margin: 0;
394 | padding: 0;
395 | }
396 | ul.order li {
397 | border-bottom: 1px solid #000;
398 | padding: 2rem 0;
399 | display: -webkit-box;
400 | display: -ms-flexbox;
401 | display: flex;
402 | font-size: 1.4rem;
403 | -webkit-box-pack: justify;
404 | -ms-flex-pack: justify;
405 | justify-content: space-between;
406 | -webkit-box-align: center;
407 | -ms-flex-align: center;
408 | align-items: center;
409 | }
410 | ul.order li:hover button {
411 | display: inline;
412 | }
413 | ul.order li button {
414 | border: 0;
415 | display: none;
416 | line-height: 1;
417 | padding: 0;
418 | }
419 | ul.order li.total {
420 | font-weight: 600;
421 | border-bottom: 3px solid #000;
422 | border-top: 3px double #000;
423 | }
424 | ul.order li.unavailable {
425 | text-decoration: line-through;
426 | background: #f8d0d2;
427 | }
428 | ul.order li .price {
429 | font-size: 1.2rem;
430 | }
431 | ul.order li span.count {
432 | position: relative;
433 | overflow: hidden;
434 | float: left;
435 | }
436 | ul.order li span.count span {
437 | display: inline-block;
438 | }
439 | .order-title {
440 | text-align: center;
441 | }
442 | .fish-edit {
443 | margin-bottom: 20px;
444 | border: 2px solid #000;
445 | overflow: hidden;
446 | display: -webkit-box;
447 | display: -ms-flexbox;
448 | display: flex;
449 | -ms-flex-wrap: wrap;
450 | flex-wrap: wrap;
451 | }
452 | .fish-edit input,
453 | .fish-edit textarea,
454 | .fish-edit select {
455 | width: 33.33%;
456 | padding: 10px;
457 | line-height: 1;
458 | font-size: 1.2rem;
459 | border: 0;
460 | border-bottom: 1px solid #000;
461 | border-right: 1px solid #000;
462 | -webkit-appearance: none;
463 | -moz-appearance: none;
464 | appearance: none;
465 | border-radius: 0;
466 | background: #fff;
467 | }
468 | .fish-edit input:focus,
469 | .fish-edit textarea:focus,
470 | .fish-edit select:focus {
471 | outline: 0;
472 | background: #fef2de;
473 | }
474 | .fish-edit textarea {
475 | width: 100%;
476 | }
477 | .fish-edit input:last-of-type {
478 | width: 100%;
479 | }
480 | .fish-edit button {
481 | width: 100%;
482 | border: 0;
483 | }
484 | .list-of-fish {
485 | border-top: 2px solid #000;
486 | border-bottom: 1px solid #000;
487 | padding-top: 5px;
488 | margin-top: 2rem;
489 | -webkit-transform: translateZ(0);
490 | transform: translateZ(0);
491 | }
492 | .menu-fish {
493 | border-bottom: 2px solid #000;
494 | border-top: 1px solid #000;
495 | padding-bottom: 2rem;
496 | padding-top: 2rem;
497 | margin-bottom: 5px;
498 | clear: both;
499 | overflow: hidden;
500 | }
501 | .menu-fish p {
502 | margin: 0;
503 | font-size: 1.8rem;
504 | }
505 | .menu-fish .fish-name {
506 | margin: 0;
507 | display: -webkit-box;
508 | display: -ms-flexbox;
509 | display: flex;
510 | -webkit-box-pack: justify;
511 | -ms-flex-pack: justify;
512 | justify-content: space-between;
513 | -webkit-box-align: center;
514 | -ms-flex-align: center;
515 | align-items: center;
516 | }
517 | .menu-fish .price {
518 | font-size: 1.4rem;
519 | -webkit-box-pack: end;
520 | -ms-flex-pack: end;
521 | justify-content: flex-end;
522 | }
523 | .menu-fish img {
524 | float: left;
525 | width: 150px;
526 | margin-right: 1rem;
527 | }
528 | button,
529 | input[type=submit] {
530 | text-transform: uppercase;
531 | background: none;
532 | border: 1px solid #000;
533 | font-weight: 600;
534 | font-size: 1.5rem;
535 | font-family: 'Open Sans';
536 | -webkit-transition: all 0.2s;
537 | transition: all 0.2s;
538 | position: relative;
539 | z-index: 2;
540 | }
541 | button[disabled],
542 | input[type=submit][disabled] {
543 | color: #d12028;
544 | background: #fff;
545 | border-color: #d12028;
546 | -webkit-transform: rotate(-10deg) scale(2) translateX(50%) translateY(-50%);
547 | transform: rotate(-10deg) scale(2) translateX(50%) translateY(-50%);
548 | }
549 | button[disabled]:hover,
550 | input[type=submit][disabled]:hover {
551 | color: #d12028;
552 | cursor: not-allowed;
553 | }
554 | button[disabled]:after,
555 | input[type=submit][disabled]:after {
556 | display: none;
557 | }
558 | button:after,
559 | input[type=submit]:after {
560 | content: '';
561 | z-index: -1;
562 | display: block;
563 | background: #000;
564 | position: absolute;
565 | width: 100%;
566 | height: 0%;
567 | left: 0;
568 | top: 0;
569 | -webkit-transition: all 0.2s;
570 | transition: all 0.2s;
571 | }
572 | button:hover,
573 | input[type=submit]:hover,
574 | button:focus,
575 | input[type=submit]:focus {
576 | color: #fff;
577 | outline: 0;
578 | }
579 | button:hover:after,
580 | input[type=submit]:hover:after,
581 | button:focus:after,
582 | input[type=submit]:focus:after {
583 | height: 100%;
584 | }
585 | button.warning:after,
586 | input[type=submit].warning:after {
587 | background: #d12028;
588 | }
589 | button.success:after,
590 | input[type=submit].success:after {
591 | background: #2dc22d;
592 | }
593 | button.github,
594 | input[type=submit].github,
595 | button.facebook,
596 | input[type=submit].facebook,
597 | button.twitter,
598 | input[type=submit].twitter {
599 | border: 0;
600 | display: block;
601 | margin-bottom: 2rem;
602 | width: 100%;
603 | color: #fff;
604 | padding: 2rem;
605 | }
606 | button.github,
607 | input[type=submit].github {
608 | background: #82d465;
609 | }
610 | button.github:after,
611 | input[type=submit].github:after {
612 | background: #5cc437;
613 | }
614 | button.facebook,
615 | input[type=submit].facebook {
616 | background: #3864a3;
617 | }
618 | button.facebook:after,
619 | input[type=submit].facebook:after {
620 | background: #2d5082;
621 | }
622 | button.twitter,
623 | input[type=submit].twitter {
624 | background: #5ea9dd;
625 | }
626 | button.twitter:after,
627 | input[type=submit].twitter:after {
628 | background: #2c8dd0;
629 | }
630 | .store-selector {
631 | background: #fff;
632 | max-width: 500px;
633 | margin: 50px auto;
634 | padding: 2rem;
635 | border: 2px solid #000;
636 | }
637 | .store-selector input,
638 | .store-selector button {
639 | width: 100%;
640 | }
641 | .store-selector input[type="text"],
642 | .store-selector button[type="text"] {
643 | text-align: center;
644 | font-size: 3rem;
645 | }
646 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/css/style.styl:
--------------------------------------------------------------------------------
1 | // Import all partials
2 | @require './_*.styl'
3 |
4 |
5 | header.top
6 | text-align center
7 | h1
8 | font-size 14.4rem
9 | line-height 0.7 // this font has a wacky baseline
10 | display flex
11 | justify-content: center;
12 |
13 | // This is a bunch of goofy CSS to make the logo look decent
14 | .ofThe
15 | display flex
16 | font-size 3rem
17 | color orange
18 | justify-content: center;
19 | align-items: center;
20 | background url('images/anchor.svg') center no-repeat;
21 | background-size cover
22 | padding 0 1rem
23 | .of
24 | padding-right 2rem
25 | position relative
26 | right -0.5rem
27 | h3
28 | margin 0
29 | font-size 2rem
30 | color orange
31 | position relative
32 | display inline-block
33 | span
34 | background white
35 | position relative
36 | z-index 2
37 | padding-left 1rem
38 | padding-right 1rem
39 | &:before, &:after
40 | display block
41 | z-index 1
42 | background black
43 | position absolute
44 | width 130%
45 | height 1px
46 | content ''
47 | top 5px
48 | margin-left -15%
49 | &:after
50 | top auto
51 | bottom 7px
52 |
53 | .catch-of-the-day
54 | display flex
55 | height 90vh
56 | max-width:1500px
57 | margin 0 auto
58 | margin-top 5vh
59 | perspective: 1000;
60 | transform-style preserve-3d
61 | & > *
62 | flex 1 4 auto
63 | padding 2rem
64 | border 1rem double lighten(black,10%)
65 | position relative
66 | background white
67 | transition all 0.3s
68 | box-shadow 0px 5px 5px rgba(0,0,0,0.1)
69 | overflow scroll
70 | &:first-child
71 | flex-shrink 1 // take 4x the extra room
72 | flex-basis 50%
73 | transform translateX(50%) rotateY(6deg) translateX(-50%)
74 | &:nth-child(2)
75 | transform translateX(-50%) rotateY(-14deg) translateX(50%)
76 | border-left 0
77 | border-right 0
78 | min-width 300px
79 | &:last-child
80 | flex-shrink 1 // take 4x the extra room
81 | flex-basis 50%
82 | transform translateX(-50%) rotateY(10deg) translateX(50%) scale(1.08) translateX(24px)
83 | // Folding Transforms
84 | // Take off folding when not checked
85 | input#fold:not(:checked) ~ #main
86 | .catch-of-the-day > *
87 | transform none
88 |
89 | label[for="fold"]
90 | position absolute
91 | top 1rem
92 | left 1rem
93 | text-transform uppercase
94 | font-size 1.3rem
95 | background black
96 | color white
97 | border 2px solid black
98 | cursor pointer
99 | padding 0.5rem 1rem
100 |
101 | input#fold
102 | display none
103 | &:checked + label
104 | background white
105 | color black
106 |
107 | ul
108 | list-style none
109 | margin 0
110 | padding 0
111 |
112 | ul.order
113 | // Default state
114 | li
115 | border-bottom 1px solid black
116 | padding 2rem 0
117 | display flex
118 | font-size 1.4rem
119 | justify-content space-between
120 | align-items center
121 | &:hover
122 | // padding 1rem 0
123 | button
124 | display inline
125 | button
126 | border 0
127 | display none
128 | line-height 1
129 | padding 0
130 | &.total
131 | font-weight 600
132 | border-bottom 3px solid black
133 | border-top 3px double black
134 | &.unavailable
135 | text-decoration line-through
136 | background lighten(red, 80%)
137 | .price
138 | font-size 1.2rem
139 | span.count
140 | position relative
141 | overflow hidden
142 | float left // only works if it's floated?!
143 | span
144 | display inline-block
145 | // transition all 0.5s
146 |
147 | .order-title
148 | text-align center
149 |
150 | .fish-edit
151 | margin-bottom 20px
152 | border 2px solid black
153 | overflow hidden
154 | display flex
155 | flex-wrap wrap
156 | input, textarea, select
157 | width 33.33%
158 | padding 10px
159 | line-height 1
160 | font-size 1.2rem
161 | border 0
162 | border-bottom 1px solid black
163 | border-right 1px solid black
164 | appearance none
165 | border-radius 0
166 | background white
167 | &:focus
168 | outline 0
169 | background lighten(orange, 85%)
170 | textarea
171 | width 100%
172 | input:last-of-type
173 | width 100%
174 | button
175 | width 100%
176 | border 0
177 | // Menu Styles
178 | .list-of-fish
179 | border-top 2px solid black
180 | border-bottom 1px solid black
181 | padding-top 5px
182 | margin-top 2rem
183 | transform translateZ(0);
184 |
185 | .menu-fish
186 | border-bottom 2px solid black
187 | border-top 1px solid black
188 | padding-bottom 2rem
189 | padding-top 2rem
190 | margin-bottom 5px
191 | clear both
192 | overflow hidden
193 | p
194 | margin 0
195 | font-size 1.8rem
196 | .fish-name
197 | margin 0
198 | display flex
199 | justify-content space-between
200 | align-items center
201 | .price
202 | font-size 1.4rem
203 | // color orange
204 | justify-content flex-end
205 | // font-family 'Open Sans Condensed'
206 | img
207 | float left
208 | width 150px
209 | margin-right 1rem
210 |
211 | button, input[type=submit]
212 | text-transform uppercase
213 | background none
214 | border 1px solid black
215 | font-weight 600
216 | font-size 1.5rem
217 | font-family 'Open Sans'
218 | transition all 0.2s
219 | position relative
220 | z-index 2
221 | &[disabled]
222 | color red
223 | background white
224 | border-color red
225 | transform rotate(-10deg) scale(2) translateX(50%) translateY(-50%)
226 | &:hover
227 | color red
228 | cursor not-allowed
229 | &:after
230 | display none
231 | &:after
232 | content ''
233 | z-index -1
234 | display block
235 | background black
236 | position absolute
237 | width 100%
238 | height 0%
239 | left 0
240 | top 0
241 | transition all 0.2s
242 | &:hover, &:focus
243 | color white
244 | outline 0
245 | &:after
246 | height 100%
247 | // variants
248 | &.warning
249 | &:after
250 | background red
251 | &.success
252 | &:after
253 | background green
254 |
255 | &.github, &.facebook, &.twitter
256 | border 0
257 | display block
258 | margin-bottom 2rem
259 | width 100%
260 | color white
261 | padding 2rem
262 | &.github
263 | background #82D465
264 | &:after
265 | background darken(#82D465, 20%)
266 | &.facebook
267 | background #3864A3
268 | &:after
269 | background darken(#3864A3, 20%)
270 | &.twitter
271 | background #5EA9DD
272 | &:after
273 | background darken(#5EA9DD, 20%)
274 | // Store Selector
275 | .store-selector
276 | background white
277 | max-width 500px
278 | margin 50px auto
279 | padding 2rem
280 | border 2px solid black
281 | input, button
282 | width 100%
283 | &[type="text"]
284 | text-align center
285 | font-size 3rem
286 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/helpers.js:
--------------------------------------------------------------------------------
1 | export function formatPrice(cents) {
2 | return `$${(cents / 100).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
3 | }
4 |
5 | export function rando(arr) {
6 | return arr[Math.floor(Math.random() * arr.length)];
7 | }
8 |
9 | export function slugify(text) {
10 | return text.toString().toLowerCase()
11 | .replace(/\s+/g, '-') // Replace spaces with -
12 | .replace(/[^\w\-]+/g, '') // Remove all non-word chars
13 | .replace(/\-\-+/g, '-') // Replace multiple - with single -
14 | .replace(/^-+/, '') // Trim - from start of text
15 | .replace(/-+$/, ''); // Trim - from end of text
16 | }
17 |
18 | export function getFunName() {
19 | const adjectives = ['adorable', 'beautiful', 'clean', 'drab', 'elegant', 'fancy', 'glamorous', 'handsome', 'long', 'magnificent', 'old-fashioned', 'plain', 'quaint', 'sparkling', 'ugliest', 'unsightly', 'angry', 'bewildered', 'clumsy', 'defeated', 'embarrassed', 'fierce', 'grumpy', 'helpless', 'itchy', 'jealous', 'lazy', 'mysterious', 'nervous', 'obnoxious', 'panicky', 'repulsive', 'scary', 'thoughtless', 'uptight', 'worried'];
20 |
21 | const nouns = ['women', 'men', 'children', 'teeth', 'feet', 'people', 'leaves', 'mice', 'geese', 'halves', 'knives', 'wives', 'lives', 'elves', 'loaves', 'potatoes', 'tomatoes', 'cacti', 'foci', 'fungi', 'nuclei', 'syllabuses', 'analyses', 'diagnoses', 'oases', 'theses', 'crises', 'phenomena', 'criteria', 'data'];
22 |
23 | return `${rando(adjectives)}-${rando(adjectives)}-${rando(nouns)}`;
24 | }
25 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import { BrowserRouter, Match, Miss } from 'react-router';
4 | import './css/style.css';
5 | import App from './components/App';
6 |
7 | import StorePicker from './components/StorePicker';
8 | import NotFound from './components/NotFound';
9 |
10 | const Root = () => {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | render( , document.querySelector('#main'));
23 |
--------------------------------------------------------------------------------
/catch-of-the-day/src/sample-fishes.js:
--------------------------------------------------------------------------------
1 | // This is just some sample data so you don't have to think of your own!
2 | module.exports = {
3 | fish1: {
4 | name: 'Pacific Halibut',
5 | image: 'http://i.istockimg.com/file_thumbview_approve/36248396/5/stock-photo-36248396-blackened-cajun-sea-bass.jpg',
6 | desc: 'Everyones favorite white fish. We will cut it to the size you need and ship it.',
7 | price: 1724,
8 | status: 'available'
9 | },
10 |
11 | fish2: {
12 | name: 'Lobster',
13 | image: 'http://i.istockimg.com/file_thumbview_approve/32135274/5/stock-photo-32135274-cooked-lobster.jpg',
14 | desc: 'These tender, mouth-watering beauties are a fantastic hit at any dinner party.',
15 | price: 3200,
16 | status: 'available'
17 | },
18 |
19 | fish3: {
20 | name: 'Sea Scallops',
21 | image: 'http://i.istockimg.com/file_thumbview_approve/58624176/5/stock-photo-58624176-scallops-on-black-stone-plate.jpg',
22 | desc: 'Big, sweet and tender. True dry-pack scallops from the icey waters of Alaska. About 8-10 per pound',
23 | price: 1684,
24 | status: 'unavailable'
25 | },
26 |
27 | fish4: {
28 | name: 'Mahi Mahi',
29 | image: 'http://i.istockimg.com/file_thumbview_approve/12556651/5/stock-photo-12556651-mahimahi.jpg',
30 | desc: 'Lean flesh with a mild, sweet flavor profile, moderately firm texture and large, moist flakes. ',
31 | price: 1129,
32 | status: 'available'
33 | },
34 |
35 | fish5: {
36 | name: 'King Crab',
37 | image: 'http://i.istockimg.com/file_thumbview_approve/18294110/5/stock-photo-18294110-king-crab-legs.jpg',
38 | desc: 'Crack these open and enjoy them plain or with one of our cocktail sauces',
39 | price: 4234,
40 | status: 'available'
41 | },
42 |
43 | fish6: {
44 | name: 'Atlantic Salmon',
45 | image: 'http://i.istockimg.com/file_thumbview_approve/56241842/5/stock-photo-56241842-salmon-fish.jpg',
46 | desc: 'This flaky, oily salmon is truly the king of the sea. Bake it, grill it, broil it...as good as it gets!',
47 | price: 1453,
48 | status: 'available'
49 | },
50 |
51 | fish7: {
52 | name: 'Oysters',
53 | image: 'http://i.istockimg.com/file_thumbview_approve/58626682/5/stock-photo-58626682-fresh-oysters-on-a-black-stone-plate-top-view.jpg',
54 | desc: 'A soft plump oyster with a sweet salty flavor and a clean finish.',
55 | price: 2543,
56 | status: 'available'
57 | },
58 |
59 | fish8: {
60 | name: 'Mussels',
61 | image: 'http://i.istockimg.com/file_thumbview_approve/40450406/5/stock-photo-40450406-steamed-mussels.jpg',
62 | desc: 'The best mussels from the Pacific Northwest with a full-flavored and complex taste.',
63 | price: 425,
64 | status: 'available'
65 | },
66 |
67 | fish9: {
68 | name: 'Jumbo Prawns',
69 | image: 'http://i.istockimg.com/file_thumbview_approve/67121439/5/stock-photo-67121439-fresh-tiger-shrimp-on-ice-on-a-black-stone-table.jpg',
70 | desc: 'With 21-25 two bite prawns in each pound, these sweet morsels are perfect for shish-kabobs.',
71 | price: 2250,
72 | status: 'available'
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # React For Beginners — [ReactForBeginners.com](https://ReactForBeginners.com)
4 |
5 | Starter files for the React For Beginners course. Come Learn React with me!
6 |
7 | The code in this repo meant to be a reference point for anyone following along with the video course.
8 |
9 | ## To Start
10 |
11 | 1. cd into `catch-of-the-day` and follow along with the videos
12 |
13 | The `stepped-solutions` Each folder contains the files for the beginning of each video should you need them. So, if you need any code, pull the appropriate file into your `catch-of-the-day` folder.
14 |
15 | You are welcome to submit Pull Requests but I'd like to keep the code as similar as possible to the course content.
16 |
17 | ### Code Use
18 |
19 | You are welcome to use this code in your own applications. If you would like to use it for training purposes, please shoot me a message first to make sure it's okay.
20 |
21 |
22 | # Frequently Asked Questions
23 |
24 | #### :question: Where are folders `2`, `3`, and `5`?
25 | Not all the videos have significant enough code changes to warrant an entire folder. Although you should be coding them all yourself, the code is available in the next video's folder.
26 |
27 | #### :question: I tried installing the Babel syntax highlighter but it didn't work!
28 |
29 | There are a few possible options:
30 |
31 | * If you are on Sublime Text 2, you should Upgrade to Sublime Text 3.
32 | * Some users have reported restarting works
33 | * You can try the [JavaScript Next](https://packagecontrol.io/packages/JavaScriptNext%20-%20ES6%20Syntax) syntax highlighter instead
34 |
35 | #### :question: I can't set Babel as the default syntax highlighter!
36 |
37 | Make sure you are in a file with the extension of `.js` before you do this step - you can't set the default for a file without having a file open!
38 |
39 | #### :question: I can't see the React tab in my dev tools
40 |
41 | Restart your dev tools or your chrome browser entirely. They will only show up when you are viewing a React app - so make sure you test it on Facebook or another website that is running React. It won't work on your empty `main.js` file until you `import React from 'react'`.
42 |
43 | #### :question: `npm start` doesn't update the app on file save, or doesn't run correctly.
44 |
45 | There may be a few different causes for this:
46 | - Webpack currently can't handle folder/file names that contain parentheses.
47 | - Webpack also has problems running inside folders for Dropbox/Google Drive type services. Git is recommended for keeping your files in sync across multiple computers.
48 |
49 | #### :question: What Sublime Text Packages are you using? What Terminal Theme?
50 |
51 | * I've written indepth over at [WesBos.com/uses](http://wesbos.com/uses)
52 | * Theme + Colour Scheme → [Cobalt 2](https://packagecontrol.io/packages/Theme%20-%20Cobalt2)
53 | * JS Syntax Highlighting → [Babel](https://packagecontrol.io/packages/Babel)
54 | * HTML + CSS Shortcuts → [Emmet](https://packagecontrol.io/packages/Emmet) — You can [get emmet working with JSX here](http://wesbos.com/emmet-react-jsx-sublime/)
55 |
--------------------------------------------------------------------------------