├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── branch-step-01-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-01
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-02-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-02
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-03-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── components
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-03
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── components
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ └── ListPage.js
└── webpack.config.js
├── branch-step-04-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-04
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-05-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ └── CreatePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-05
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ └── CreatePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-06-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ ├── CreatePokemonMutation.js
│ │ └── DeletePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-06
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ ├── CreatePokemonMutation.js
│ │ └── DeletePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-07-solution
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ ├── CreatePokemonMutation.js
│ │ ├── DeletePokemonMutation.js
│ │ └── UpdatePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── branch-step-07
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ ├── CreatePokemonMutation.js
│ │ ├── DeletePokemonMutation.js
│ │ └── UpdatePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── hosted-demo
├── .babelrc
├── .eslintrc
├── .gitignore
├── .jshintrc
├── .netlify
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── public
│ └── _redirects
├── src
│ ├── assets
│ │ └── delete.svg
│ ├── components
│ │ ├── AddNew.css
│ │ ├── AddNew.js
│ │ ├── PokemonCard.css
│ │ ├── PokemonCard.js
│ │ ├── PokemonPreview.css
│ │ └── PokemonPreview.js
│ ├── index.css
│ ├── index.js
│ ├── mutations
│ │ ├── CreatePokemonMutation.js
│ │ ├── DeletePokemonMutation.js
│ │ └── UpdatePokemonMutation.js
│ └── views
│ │ ├── ListPage.css
│ │ ├── ListPage.js
│ │ ├── PokemonPage.css
│ │ └── PokemonPage.js
└── webpack.config.js
├── pokedex.schema
└── update-branches.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | */node_modules
2 | node_modules
3 | .idea
4 | .DB_Store
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pokedex
2 |
3 | Pokedex example app using and teaching Relay and GraphQL
4 |
5 | > **Live Demo: [http://demo.learnrelay.org](http://demo.learnrelay.org/)**
6 |
7 | 
8 |
9 | ## Getting started
10 |
11 | If you haven't done it already, checkout the [interactive Learn Relay tutorial](https://www.learnrelay.org/).
12 |
13 | ```sh
14 | git clone git@github.com:learnrelay/pokedex.git
15 | cd pokedex
16 | git checkout step-01
17 | npm install
18 | npm start # open localhost:3000
19 | ```
20 |
21 | ## Workflow
22 |
23 | As you're following along the chapters in Learn Relay, you will work on seven small coding excercises each called a "step". Each step and its solution is available in this repository as an individual branch where you can jump between if needed.
24 |
25 | Let's say you want to start with step 3, so you would run `git checkout step-03`. In case you're not too familiar with `git`, this command switches you over to the `step-03` branch. The `node_modules` folder doesn't change, that means you don't need to run `npm install` again.
26 |
27 | After you completed the step, you can compare your results to the official solution by running `git diff origin/step-03-solution`. In the best possible case this command shouldn't give you any output which means your and our solution are identical. It can happen that you found a different solution than we're proposing. That's totally fine, just continue with the next step and feel free to [tell us](http://slack.graph.cool/) about your solution. 💡
28 |
29 | ## Help & Community [](https://slack.graph.cool)
30 |
31 | Join our [Slack community](http://slack.graph.cool/) if you run into issues or have questions. We love talking to you!
32 |
33 | 
34 |
--------------------------------------------------------------------------------
/branch-step-01-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-01-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-01-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-01-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-01-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-01-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-01-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-01-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-01-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-01-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
14 |
15 | ReactDOM.render(
16 |
22 |
23 |
24 | , document.getElementById('root')
25 | )
26 |
--------------------------------------------------------------------------------
/branch-step-01-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-01-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './ListPage.css'
3 |
4 | export default class ListPage extends React.Component {
5 | static propTypes = {
6 | viewer: React.PropTypes.object,
7 | }
8 | render () {
9 | return (
10 |
11 | I am a REACT app!
12 |
13 | )
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/branch-step-01-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-01/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-01/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-01/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-01/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-01/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-01/favicon.ico
--------------------------------------------------------------------------------
/branch-step-01/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-01/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-01/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-01/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | ReactDOM.render(
14 |
20 |
21 |
22 | , document.getElementById('root')
23 | )
24 |
--------------------------------------------------------------------------------
/branch-step-01/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-01/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './ListPage.css'
3 |
4 | export default class ListPage extends React.Component {
5 | static propTypes = {
6 | viewer: React.PropTypes.object,
7 | }
8 | render () {
9 | return (
10 |
11 | I am a REACT app!
12 |
13 | )
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/branch-step-01/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-02-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-02-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-02-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-02-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-02-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-02-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-02-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-02-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-02-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-02-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
14 |
15 | ReactDOM.render(
16 |
22 |
23 |
24 | , document.getElementById('root')
25 | )
26 |
--------------------------------------------------------------------------------
/branch-step-02-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-02-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import classes from './ListPage.css'
4 |
5 | class ListPage extends React.Component {
6 | static propTypes = {
7 | viewer: React.PropTypes.object,
8 | }
9 | render () {
10 | return (
11 |
12 | {`Your viewer id is: ${this.props.viewer.id}`}
13 |
14 | )
15 | }
16 | }
17 |
18 | export default Relay.createContainer(
19 | ListPage,
20 | {
21 | fragments: {
22 | viewer: () => Relay.QL`
23 | fragment on Viewer {
24 | id
25 | }
26 | `,
27 | },
28 | },
29 | )
30 |
--------------------------------------------------------------------------------
/branch-step-02-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-02/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-02/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-02/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-02/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-02/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-02/favicon.ico
--------------------------------------------------------------------------------
/branch-step-02/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-02/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-02/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-02/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | ReactDOM.render(
14 |
20 |
21 |
22 | , document.getElementById('root')
23 | )
24 |
--------------------------------------------------------------------------------
/branch-step-02/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-02/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './ListPage.css'
3 |
4 | export default class ListPage extends React.Component {
5 | static propTypes = {
6 | viewer: React.PropTypes.object,
7 | }
8 | render () {
9 | return (
10 |
11 | I am a REACT app!
12 |
13 | )
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/branch-step-02/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-03-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-03-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-03-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-03-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-03-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-03-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-03-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-03-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import classes from './PokemonPreview.css'
4 |
5 | class PokemonPreview extends React.Component {
6 |
7 | static propTypes = {
8 | pokemon: React.PropTypes.object,
9 | router: React.PropTypes.object,
10 | }
11 |
12 | render () {
13 | return (
14 |
15 |
16 |

17 |
18 | {this.props.pokemon.name}
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default Relay.createContainer(
27 | PokemonPreview,
28 | {
29 | fragments: {
30 | pokemon: () => Relay.QL`
31 | fragment on Pokemon {
32 | id
33 | name
34 | url
35 | }
36 | `,
37 | },
38 | }
39 | )
40 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
14 |
15 | ReactDOM.render(
16 |
22 |
23 |
24 | , document.getElementById('root')
25 | )
26 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-03-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import classes from './ListPage.css'
5 |
6 | class ListPage extends React.Component {
7 | static propTypes = {
8 | viewer: React.PropTypes.object,
9 | }
10 | render () {
11 | return (
12 |
13 |
14 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
15 |
16 |
17 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
18 |
19 | )
20 | }
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | ListPage,
29 | {
30 | fragments: {
31 | viewer: () => Relay.QL`
32 | fragment on Viewer {
33 | allPokemons (first: 1000) {
34 | edges {
35 | node {
36 | ${PokemonPreview.getFragment('pokemon')}
37 | id
38 | }
39 | }
40 | }
41 | id
42 | }
43 | `,
44 | },
45 | },
46 | )
47 |
--------------------------------------------------------------------------------
/branch-step-03-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-03/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-03/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-03/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-03/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-03/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-03/favicon.ico
--------------------------------------------------------------------------------
/branch-step-03/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-03/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-03/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-03/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import classes from './PokemonPreview.css'
4 |
5 | class PokemonPreview extends React.Component {
6 |
7 | static propTypes = {
8 | pokemon: React.PropTypes.object,
9 | router: React.PropTypes.object,
10 | }
11 |
12 | render () {
13 | return (
14 |
15 |
16 |

17 |
18 | {this.props.pokemon.name}
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default Relay.createContainer(
27 | PokemonPreview,
28 | {
29 | fragments: {
30 | pokemon: () => Relay.QL`
31 | fragment on Pokemon {
32 | id
33 | name
34 | url
35 | }
36 | `,
37 | },
38 | }
39 | )
40 |
--------------------------------------------------------------------------------
/branch-step-03/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-03/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import ListPage from './views/ListPage'
5 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
6 | import useRelay from 'react-router-relay'
7 | import './index.css'
8 |
9 | Relay.injectNetworkLayer(
10 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
11 | )
12 |
13 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
14 |
15 | ReactDOM.render(
16 |
22 |
23 |
24 | , document.getElementById('root')
25 | )
26 |
--------------------------------------------------------------------------------
/branch-step-03/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-03/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import classes from './ListPage.css'
5 |
6 | class ListPage extends React.Component {
7 | static propTypes = {
8 | viewer: React.PropTypes.object,
9 | }
10 | render () {
11 | return (
12 |
13 |
14 | {`There are 28 Pokemons in your pokedex`}
15 |
16 |
17 | {/* Iterate through pokemon here */}
18 |
19 |
20 | )
21 | }
22 | }
23 |
24 | export default Relay.createContainer(
25 | ListPage,
26 | {
27 | fragments: {
28 | viewer: () => Relay.QL`
29 | fragment on Viewer {
30 | id
31 | }
32 | `,
33 | },
34 | },
35 | )
36 |
--------------------------------------------------------------------------------
/branch-step-03/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-04-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-04-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-04-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-04-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-04-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-04-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-04-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-04-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-04-solution/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-04-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-04/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-04/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-04/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-04/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-04/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-04/favicon.ico
--------------------------------------------------------------------------------
/branch-step-04/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-04/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-04/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-04/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-04/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './AddNew.css'
3 |
4 | export default class AddNew extends React.Component {
5 |
6 | render () {
7 | return (
8 |
9 |
10 |
11 | +
12 |
13 |
14 | Add New
15 |
16 |
17 |
18 | )
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-04/src/components/PokemonCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './PokemonCard.css'
3 |
4 | export default class PokemonCard extends React.Component {
5 |
6 | static propTypes = {
7 | addNew: React.PropTypes.bool,
8 | url: React.PropTypes.string,
9 | name: React.PropTypes.string,
10 | onNameChange: React.PropTypes.func,
11 | onUrlChange: React.PropTypes.func,
12 | }
13 |
14 | render () {
15 | return (
16 |
17 |
18 |
19 | NAME
20 |
21 |
this.props.onNameChange(e.target.value)}
26 | />
27 |
28 |
29 |
30 |
31 | IMAGE URL
32 |
33 |
this.props.onUrlChange(e.target.value)}
38 | />
39 |
40 |
41 |

42 |
43 |
44 |
45 | )
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/branch-step-04/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-04/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import classes from './PokemonPreview.css'
4 |
5 | class PokemonPreview extends React.Component {
6 |
7 | static propTypes = {
8 | pokemon: React.PropTypes.object,
9 | router: React.PropTypes.object,
10 | }
11 |
12 | render () {
13 | return (
14 |
15 |
16 |

17 |
18 | {this.props.pokemon.name}
19 |
20 |
21 |
22 | )
23 | }
24 | }
25 |
26 | export default Relay.createContainer(
27 | PokemonPreview,
28 | {
29 | fragments: {
30 | pokemon: () => Relay.QL`
31 | fragment on Pokemon {
32 | id
33 | name
34 | url
35 | }
36 | `,
37 | },
38 | }
39 | )
40 |
--------------------------------------------------------------------------------
/branch-step-04/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-04/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 | , document.getElementById('root')
26 | )
27 |
--------------------------------------------------------------------------------
/branch-step-04/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-04/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-04/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-04/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-05-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-05-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-05-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-05-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-05-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-05-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-05-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-05-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class CreatePokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 | return {
51 | edge: {
52 | node: {
53 | name: this.props.name,
54 | url: this.props.url,
55 | },
56 | },
57 | viewer: {
58 | id: this.props.viewer.id,
59 | },
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-05-solution/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-05-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-05/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-05/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-05/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-05/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-05/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-05/favicon.ico
--------------------------------------------------------------------------------
/branch-step-05/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-05/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-05/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-05/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-05/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/branch-step-05/src/components/PokemonCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './PokemonCard.css'
3 |
4 | export default class PokemonCard extends React.Component {
5 |
6 | static propTypes = {
7 | addNew: React.PropTypes.bool,
8 | url: React.PropTypes.string,
9 | name: React.PropTypes.string,
10 | onNameChange: React.PropTypes.func,
11 | onUrlChange: React.PropTypes.func,
12 | }
13 |
14 | render () {
15 | return (
16 |
17 |
18 |
19 | NAME
20 |
21 |
this.props.onNameChange(e.target.value)}
26 | />
27 |
28 |
29 |
30 |
31 | IMAGE URL
32 |
33 |
this.props.onUrlChange(e.target.value)}
38 | />
39 |
40 |
41 |

42 |
43 |
44 |
45 | )
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/branch-step-05/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-05/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-05/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-05/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-05/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class CreatePokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 |
7 | }
8 |
9 | getMutation () {
10 |
11 | }
12 |
13 | getFatQuery () {
14 |
15 | }
16 |
17 | getConfigs () {
18 | return [{
19 | type: 'RANGE_ADD',
20 | parentName: 'viewer',
21 | parentID: this.props.viewer.id,
22 | connectionName: 'allPokemons',
23 | edgeName: 'edge',
24 | rangeBehaviors: {
25 | '': 'append',
26 | },
27 | }]
28 | }
29 |
30 | getVariables () {
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-05/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-05/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-05/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-05/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-06-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-06-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-06-solution/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-06-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-06-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-06-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-06-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-06-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class CreatePokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 | return {
51 | edge: {
52 | node: {
53 | name: this.props.name,
54 | url: this.props.url,
55 | },
56 | },
57 | viewer: {
58 | id: this.props.viewer.id,
59 | },
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/mutations/DeletePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class DeletePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{deletePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on DeletePokemonPayload {
12 | viewer
13 | deletedId
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'NODE_DELETE',
21 | parentName: 'viewer',
22 | parentID: this.props.viewerId,
23 | connectionName: 'pokemon',
24 | deletedIDFieldName: 'deletedId',
25 | }]
26 | }
27 |
28 | getVariables () {
29 | return {
30 | id: this.props.pokemonId,
31 | }
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-06-solution/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-06-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-06/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-06/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-06/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | logs
3 | *.log
4 | npm-debug.log*
5 | .idea
6 | .DB_Store
--------------------------------------------------------------------------------
/branch-step-06/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-06/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-06/favicon.ico
--------------------------------------------------------------------------------
/branch-step-06/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-06/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-06/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-06/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-06/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/branch-step-06/src/components/PokemonCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './PokemonCard.css'
3 |
4 | export default class PokemonCard extends React.Component {
5 |
6 | static propTypes = {
7 | addNew: React.PropTypes.bool,
8 | url: React.PropTypes.string,
9 | name: React.PropTypes.string,
10 | onNameChange: React.PropTypes.func,
11 | onUrlChange: React.PropTypes.func,
12 | }
13 |
14 | render () {
15 | return (
16 |
17 |
18 |
19 | NAME
20 |
21 |
this.props.onNameChange(e.target.value)}
26 | />
27 |
28 |
29 |
30 |
31 | IMAGE URL
32 |
33 |
this.props.onUrlChange(e.target.value)}
38 | />
39 |
40 |
41 |

42 |
43 |
44 |
45 | )
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/branch-step-06/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-06/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-06/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-06/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-06/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class CreatePokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 | return {
51 | edge: {
52 | node: {
53 | name: this.props.name,
54 | url: this.props.url,
55 | },
56 | },
57 | viewer: {
58 | id: this.props.viewer.id,
59 | },
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/branch-step-06/src/mutations/DeletePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class DeletePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 |
7 | }
8 |
9 | getFatQuery () {
10 |
11 | }
12 |
13 | getConfigs () {
14 |
15 | }
16 |
17 | getVariables () {
18 |
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-06/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-06/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-06/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-06/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-07-solution/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-07-solution/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-07-solution/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
13 | #IDE
14 | .idea/*
15 |
--------------------------------------------------------------------------------
/branch-step-07-solution/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-07-solution/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-07-solution/favicon.ico
--------------------------------------------------------------------------------
/branch-step-07-solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-07-solution/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class AddPokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 | return {
51 | edge: {
52 | node: {
53 | name: this.props.name,
54 | url: this.props.url,
55 | },
56 | },
57 | viewer: {
58 | id: this.props.viewer.id,
59 | },
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/mutations/DeletePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class DeletePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{deletePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on DeletePokemonPayload {
12 | viewer
13 | deletedId
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'NODE_DELETE',
21 | parentName: 'viewer',
22 | parentID: this.props.viewerId,
23 | connectionName: 'pokemon',
24 | deletedIDFieldName: 'deletedId',
25 | }]
26 | }
27 |
28 | getVariables () {
29 | return {
30 | id: this.props.pokemonId,
31 | }
32 | }
33 |
34 | getOptimisticResponse () {
35 | return {
36 | deletedId: this.props.pokemonId,
37 | }
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/mutations/UpdatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class UpdatePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{updatePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on UpdatePokemonPayload {
12 | viewer
13 | pokemon
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'FIELDS_CHANGE',
21 | fieldIDs: {
22 | pokemon: this.props.pokemonId,
23 | },
24 | }]
25 | }
26 |
27 | getVariables () {
28 | return {
29 | id: this.props.pokemonId,
30 | name: this.props.name,
31 | url: this.props.url,
32 | }
33 | }
34 |
35 | getOptimisticResponse () {
36 | return {
37 | model: {
38 | id: this.props.pokemonId,
39 | name: this.props.name,
40 | url: this.props.url,
41 | },
42 | }
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-07-solution/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-07-solution/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/branch-step-07/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/branch-step-07/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/branch-step-07/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
13 | #IDE
14 | .idea/*
15 |
--------------------------------------------------------------------------------
/branch-step-07/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/branch-step-07/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/branch-step-07/favicon.ico
--------------------------------------------------------------------------------
/branch-step-07/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/branch-step-07/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/__PROJECT_ID__"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/branch-step-07/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
52 |
--------------------------------------------------------------------------------
/branch-step-07/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-07/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/branch-step-07/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/branch-step-07/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/branch-step-07/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/branch-step-07/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/__PROJECT_ID__')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/branch-step-07/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class CreatePokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/branch-step-07/src/mutations/DeletePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class DeletePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{deletePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on DeletePokemonPayload {
12 | viewer
13 | deletedId
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'NODE_DELETE',
21 | parentName: 'viewer',
22 | parentID: this.props.viewerId,
23 | connectionName: 'pokemon',
24 | deletedIDFieldName: 'deletedId',
25 | }]
26 | }
27 |
28 | getVariables () {
29 | return {
30 | id: this.props.pokemonId,
31 | }
32 | }
33 |
34 | getOptimisticResponse () {
35 |
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/branch-step-07/src/mutations/UpdatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class UpdatePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 |
7 | }
8 |
9 | getFatQuery () {
10 |
11 | }
12 |
13 | getConfigs () {
14 |
15 | }
16 |
17 | getVariables () {
18 |
19 | }
20 |
21 | getOptimisticResponse () {
22 |
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/branch-step-07/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .container {
16 | margin-left: 130px;
17 | margin-right: 130px;
18 | justify-content: center;
19 | /*align-content: stretch;*/
20 | display:flex;
21 | flex-wrap: wrap;
22 | align-items: stretch;
23 | }
24 |
--------------------------------------------------------------------------------
/branch-step-07/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
25 | )
26 | }
27 | }
28 |
29 | export default Relay.createContainer(
30 | ListPage,
31 | {
32 | fragments: {
33 | viewer: () => Relay.QL`
34 | fragment on Viewer {
35 | allPokemons (first: 1000) {
36 | edges {
37 | node {
38 | ${PokemonPreview.getFragment('pokemon')}
39 | id
40 | }
41 | }
42 | }
43 | id
44 | }
45 | `,
46 | },
47 | },
48 | )
49 |
--------------------------------------------------------------------------------
/branch-step-07/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/branch-step-07/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/hosted-demo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["react-relay"],
3 | "presets": ["react", "es2015", "stage-0"]
4 | }
5 |
--------------------------------------------------------------------------------
/hosted-demo/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": [
4 | "standard",
5 | "standard-react"
6 | ],
7 | "env": {
8 | "browser": true
9 | },
10 | "rules": {
11 | "semi": [2, "never"],
12 | "comma-dangle": [2, "always-multiline"],
13 | "space-infix-ops": 0,
14 | "max-len": [2, 120, 2],
15 | "react/jsx-no-bind": [1, {
16 | "allowArrowFunctions": true
17 | }],
18 | "jsx-quotes": [2, "prefer-single"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/hosted-demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
13 | #IDE
14 | .idea/*
15 |
--------------------------------------------------------------------------------
/hosted-demo/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": true
3 | }
4 |
--------------------------------------------------------------------------------
/hosted-demo/.netlify:
--------------------------------------------------------------------------------
1 | {"site_id":"666e6f72-b068-4225-81d4-fdd74e17e701","path":"build"}
--------------------------------------------------------------------------------
/hosted-demo/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/learnrelay/pokedex/c4d2680cb23a047a3900fe22eeb56049089f1664/hosted-demo/favicon.ico
--------------------------------------------------------------------------------
/hosted-demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pokedex App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/hosted-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "start": "webpack-dev-server -d --hot --inline --history-api-fallback --no-info --port 3000",
5 | "build": "webpack -d --inline --history-api-fallback --config webpack.config.js"
6 | },
7 | "graphql": {
8 | "request": {
9 | "url": "https://api.graph.cool/relay/v1/cj0krqsbvu90z0133orcqpse4"
10 | }
11 | },
12 | "dependencies": {
13 | "classnames": "2.2.5",
14 | "file-loader": "^0.9.0",
15 | "graphql-config-parser": "^1.0.1",
16 | "history": "3.0.0",
17 | "react": "15.2.1",
18 | "react-dom": "15.2.1",
19 | "react-relay": "^0.9.2",
20 | "react-router": "2.5.2",
21 | "react-router-relay": "0.13.3"
22 | },
23 | "devDependencies": {
24 | "babel-cli": "6.10.1",
25 | "babel-core": "^6.10.4",
26 | "babel-eslint": "^6.1.2",
27 | "babel-loader": "6.2.4",
28 | "babel-plugin-react-relay": "^0.9.3-3",
29 | "babel-preset-es2015": "6.9.0",
30 | "babel-preset-react": "6.11.1",
31 | "babel-preset-stage-0": "6.5.0",
32 | "css-loader": "^0.23.1",
33 | "eslint": "3.0.1",
34 | "eslint-config-standard": "^5.3.5",
35 | "eslint-config-standard-react": "^3.0.0",
36 | "eslint-loader": "^1.4.1",
37 | "eslint-plugin-babel": "^3.3.0",
38 | "eslint-plugin-promise": "^2.0.0",
39 | "eslint-plugin-react": "^5.2.2",
40 | "eslint-plugin-standard": "^2.0.0",
41 | "html-webpack-plugin": "^2.22.0",
42 | "style-loader": "^0.13.1",
43 | "webpack": "1.13.1",
44 | "webpack-dev-server": "1.14.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/hosted-demo/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/hosted-demo/src/assets/delete.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/hosted-demo/src/components/AddNew.css:
--------------------------------------------------------------------------------
1 | .page {
2 | background-color: transparent;
3 | /*height: auto;*/
4 | width: 180px;
5 | transition: transform 0.2s;
6 | cursor: pointer;
7 | border: dashed #d4d4d4;
8 | color: #d4d4d4;
9 | box-sizing: border-box;
10 | border-radius: 3px;
11 | /*height: 100%;*/
12 | display: flex;
13 | flex-direction: column;
14 | justify-content: center;
15 | transition: border-color .2s ease, color .2s ease;
16 | }
17 |
18 | .page:hover {
19 | border-color: #bcbcbc;
20 | color: #bcbcbc;
21 | }
22 |
23 | .link {
24 | text-decoration: none;
25 | padding: 10px;
26 | min-height: 250px;
27 | display: flex;
28 | }
29 |
30 | .plus {
31 | text-align: center;
32 | font-size: 70px;
33 | line-height: 1;
34 | font-weight: 300;
35 | }
36 |
37 | .title {
38 | margin-top: 14px;
39 | text-align: center;
40 | font-size: 24px;
41 | user-select: none;
42 | font-weight: 300;
43 | }
44 |
--------------------------------------------------------------------------------
/hosted-demo/src/components/AddNew.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Link} from 'react-router'
3 | import classes from './AddNew.css'
4 |
5 | export default class AddNew extends React.Component {
6 |
7 | render () {
8 | return (
9 |
10 |
11 |
12 | +
13 |
14 |
15 | Add New
16 |
17 |
18 |
19 | )
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/hosted-demo/src/components/PokemonCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import classes from './PokemonCard.css'
3 |
4 | export default class PokemonCard extends React.Component {
5 |
6 | static propTypes = {
7 | addNew: React.PropTypes.bool,
8 | url: React.PropTypes.string,
9 | name: React.PropTypes.string,
10 | onNameChange: React.PropTypes.func,
11 | onUrlChange: React.PropTypes.func,
12 | }
13 |
14 | render () {
15 | return (
16 |
17 |
18 |
19 | NAME
20 |
21 |
this.props.onNameChange(e.target.value)}
26 | />
27 |
28 |
29 |
30 |
31 | IMAGE URL
32 |
33 |
this.props.onUrlChange(e.target.value)}
38 | />
39 |
40 |
41 |

42 |
43 |
44 |
45 | )
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/hosted-demo/src/components/PokemonPreview.css:
--------------------------------------------------------------------------------
1 | .previewPage{
2 | background-color: white;
3 | border-radius: 3px;
4 | box-shadow: 0 2px 8px 0 rgba(0,0,0,0.25);
5 | width: 180px;
6 | cursor: pointer;
7 | display: flex;
8 | flex-direction: column;
9 | justify-content: space-between;
10 | padding: 20px;
11 | box-sizing: border-box;
12 | /*height: 100%;*/
13 | transition: transform .2s ease, box-shadow .2s ease;
14 | backface-visibility: hidden;
15 | }
16 |
17 | .previewImg {
18 | height: auto;
19 | display: block;
20 | width: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | .previewPage:hover{
25 | transform: scale(1.05);
26 | box-shadow: 0 4px 14px 0 rgba(0,0,0,0.15);
27 | }
28 |
29 | .previewName {
30 | text-align: center;
31 | color: #7F7F7F;
32 | font-size: 24px;
33 | user-select: none;
34 | font-weight: 300;
35 | padding: 20px 0 0;
36 | }
37 |
38 | .link {
39 | position: relative;
40 | text-decoration: none;
41 | padding: 10px;
42 | display: flex;
43 | }
44 |
--------------------------------------------------------------------------------
/hosted-demo/src/components/PokemonPreview.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import { Link } from 'react-router'
4 | import classes from './PokemonPreview.css'
5 |
6 | class PokemonPreview extends React.Component {
7 |
8 | static propTypes = {
9 | pokemon: React.PropTypes.object,
10 | router: React.PropTypes.object,
11 | }
12 |
13 | render () {
14 | return (
15 |
16 |
17 |

18 |
19 | {this.props.pokemon.name}
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
27 | export default Relay.createContainer(
28 | PokemonPreview,
29 | {
30 | fragments: {
31 | pokemon: () => Relay.QL`
32 | fragment on Pokemon {
33 | id
34 | name
35 | url
36 | }
37 | `,
38 | },
39 | }
40 | )
41 |
--------------------------------------------------------------------------------
/hosted-demo/src/index.css:
--------------------------------------------------------------------------------
1 | @import 'https://fonts.googleapis.com/css?family=Open+Sans:300,400';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | font-family: 'Open Sans', sans-serif;
7 | }
8 |
--------------------------------------------------------------------------------
/hosted-demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import ReactDOM from 'react-dom'
4 | import PokemonPage from './views/PokemonPage'
5 | import ListPage from './views/ListPage'
6 | import { Router, Route, browserHistory, applyRouterMiddleware } from 'react-router'
7 | import useRelay from 'react-router-relay'
8 | import './index.css'
9 |
10 | Relay.injectNetworkLayer(
11 | new Relay.DefaultNetworkLayer('https://api.graph.cool/relay/v1/cj0krqsbvu90z0133orcqpse4')
12 | )
13 |
14 | const ViewerQueries = { viewer: () => Relay.QL`query { viewer }` }
15 |
16 | ReactDOM.render(
17 |
23 |
24 |
25 |
26 |
27 | , document.getElementById('root')
28 | )
29 |
--------------------------------------------------------------------------------
/hosted-demo/src/mutations/CreatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class AddPokemonMutation extends Relay.Mutation {
4 |
5 | static fragments = {
6 | viewer: () => Relay.QL`
7 | fragment on Viewer {
8 | id
9 | }
10 | `,
11 | }
12 |
13 | getMutation () {
14 | return Relay.QL`mutation{createPokemon}`
15 | }
16 |
17 | getFatQuery () {
18 | return Relay.QL`
19 | fragment on CreatePokemonPayload {
20 | pokemon
21 | edge
22 | viewer {
23 | allPokemons
24 | }
25 | }
26 | `
27 | }
28 |
29 | getConfigs () {
30 | return [{
31 | type: 'RANGE_ADD',
32 | parentName: 'viewer',
33 | parentID: this.props.viewer.id,
34 | connectionName: 'allPokemons',
35 | edgeName: 'edge',
36 | rangeBehaviors: {
37 | '': 'append',
38 | },
39 | }]
40 | }
41 |
42 | getVariables () {
43 | return {
44 | name: this.props.name,
45 | url: this.props.url,
46 | }
47 | }
48 |
49 | getOptimisticResponse () {
50 | return {
51 | edge: {
52 | node: {
53 | name: this.props.name,
54 | url: this.props.url,
55 | },
56 | },
57 | viewer: {
58 | id: this.props.viewer.id,
59 | },
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/hosted-demo/src/mutations/DeletePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class DeletePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{deletePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on DeletePokemonPayload {
12 | viewer
13 | deletedId
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'NODE_DELETE',
21 | parentName: 'viewer',
22 | parentID: this.props.viewerId,
23 | connectionName: 'pokemon',
24 | deletedIDFieldName: 'deletedId',
25 | }]
26 | }
27 |
28 | getVariables () {
29 | return {
30 | id: this.props.pokemonId,
31 | }
32 | }
33 |
34 | getOptimisticResponse () {
35 | return {
36 | deletedId: this.props.pokemonId,
37 | }
38 | }
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/hosted-demo/src/mutations/UpdatePokemonMutation.js:
--------------------------------------------------------------------------------
1 | import Relay from 'react-relay'
2 |
3 | export default class UpdatePokemonMutation extends Relay.Mutation {
4 |
5 | getMutation () {
6 | return Relay.QL`mutation{updatePokemon}`
7 | }
8 |
9 | getFatQuery () {
10 | return Relay.QL`
11 | fragment on UpdatePokemonPayload {
12 | viewer
13 | pokemon
14 | }
15 | `
16 | }
17 |
18 | getConfigs () {
19 | return [{
20 | type: 'FIELDS_CHANGE',
21 | fieldIDs: {
22 | pokemon: this.props.pokemonId,
23 | },
24 | }]
25 | }
26 |
27 | getVariables () {
28 | return {
29 | id: this.props.pokemonId,
30 | name: this.props.name,
31 | url: this.props.url,
32 | }
33 | }
34 |
35 | getOptimisticResponse () {
36 | return {
37 | model: {
38 | id: this.props.pokemonId,
39 | name: this.props.name,
40 | url: this.props.url,
41 | },
42 | }
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/hosted-demo/src/views/ListPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: #F2F2F2;
3 | min-height: 100vh;
4 | }
5 |
6 | .title {
7 | color: #7F7F7F;
8 | font-size: 32px;
9 | text-align: center;
10 | padding-top: 120px;
11 | padding-bottom: 50px;
12 | font-weight: 300;
13 | }
14 |
15 | .footer {
16 | color: #7F7F7F;
17 | font-size: 16px;
18 | text-align: center;
19 | padding-top: 120px;
20 | padding-bottom: 50px;
21 | font-weight: 300;
22 | }
23 |
24 | .container {
25 | margin-left: 130px;
26 | margin-right: 130px;
27 | justify-content: center;
28 | /*align-content: stretch;*/
29 | display:flex;
30 | flex-wrap: wrap;
31 | align-items: stretch;
32 | }
33 |
--------------------------------------------------------------------------------
/hosted-demo/src/views/ListPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Relay from 'react-relay'
3 | import PokemonPreview from '../components/PokemonPreview'
4 | import AddNew from '../components/AddNew'
5 | import classes from './ListPage.css'
6 |
7 | class ListPage extends React.Component {
8 | static propTypes = {
9 | viewer: React.PropTypes.object,
10 | }
11 | render () {
12 | return (
13 |
14 |
15 | {`There are ${this.props.viewer.allPokemons.edges.length} Pokemons in your pokedex`}
16 |
17 |
18 | {this.props.viewer.allPokemons.edges.map((edge) => edge.node).map((pokemon) =>
19 |
20 | )
21 | }
22 |
23 |
24 |
28 |
29 | )
30 | }
31 | }
32 |
33 | export default Relay.createContainer(
34 | ListPage,
35 | {
36 | fragments: {
37 | viewer: () => Relay.QL`
38 | fragment on Viewer {
39 | allPokemons (first: 1000) {
40 | edges {
41 | node {
42 | ${PokemonPreview.getFragment('pokemon')}
43 | id
44 | }
45 | }
46 | }
47 | id
48 | }
49 | `,
50 | },
51 | },
52 | )
53 |
--------------------------------------------------------------------------------
/hosted-demo/src/views/PokemonPage.css:
--------------------------------------------------------------------------------
1 | .root {
2 | width: 100vw;
3 | height: 100vh;
4 | display: flex;
5 | background-color: #F1F1F1;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .content {
11 | width: 350px;
12 | display: flex;
13 | flex-direction: column;
14 | /*height: 75vh;*/
15 | }
16 |
17 | .buttonContainer {
18 | margin: 25px 0;
19 | display: flex;
20 | flex-direction: row;
21 | justify-content: space-between;
22 | flex: 0 0 auto;
23 | align-items: center;
24 | }
25 |
26 | .buttonContainer img {
27 | display: block;
28 | }
29 |
30 | .actionButtonContainer {
31 | display: flex;
32 | justify-content: space-between;
33 | flex-direction: row;
34 | }
35 |
36 | .deleteIcon {
37 | height: 18px;
38 | padding: 10px;
39 | cursor: hand;
40 | cursor: pointer;
41 | }
42 |
43 | .button {
44 | height: 18px;
45 | line-height: 1;
46 | font-size: 18px;
47 | padding: 15px 30px;
48 | cursor: pointer;
49 | flex: 0 0 auto;
50 | font-weight: 300;
51 | }
52 |
53 | .cancelButton {
54 | color: #A3A3A3;
55 | }
56 |
57 | .link {
58 | position: relative;
59 | text-decoration: none;
60 | padding: 10px;
61 | display: flex;
62 | }
63 |
64 | .saveButton {
65 | border-radius: 3px;
66 | color: white;
67 | background-color: #2BC3A1;
68 | }
69 |
70 | .saveButton:hover {
71 | color: #2BC3A1;
72 | background-color: white;
73 | }
74 |
--------------------------------------------------------------------------------
/hosted-demo/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 |
3 | module.exports = {
4 | entry: './src/index.js',
5 | output: {
6 | filename: '[name].[hash].js',
7 | path: __dirname + '/build',
8 | publicPath: '/'
9 | },
10 | module: {
11 | preLoaders: [{
12 | test: /\.js$/,
13 | loader: 'eslint',
14 | exclude: /node_modules/
15 | }],
16 | loaders: [{
17 | test: /\.css/,
18 | loader: 'style?sourceMap!css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
19 | }, {
20 | test: /\.js$/,
21 | loader: 'babel',
22 | exclude: /node_modules/
23 | }, {
24 | test: /\.svg$/,
25 | loader: 'file'
26 | }]
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: 'index.html'
31 | })
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/pokedex.schema:
--------------------------------------------------------------------------------
1 | type Pokemon {
2 | id: ID!
3 | name: String!
4 | url: String!
5 | }
6 |
--------------------------------------------------------------------------------
/update-branches.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | set -e
4 |
5 | message="$1"
6 |
7 | for dir in branch-step-*
8 | do
9 | cp -r $dir tmp
10 | cp -rf .git tmp
11 | cd tmp
12 | branch=${dir/"branch-"/""}
13 | git checkout -B $branch
14 | git add .
15 | git commit -m "$message"
16 | git push -f origin $branch
17 | cd ..
18 | rm -rf tmp
19 | done
20 |
--------------------------------------------------------------------------------