├── .babelrc
├── .gitignore
├── LICENSE
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── images
│ ├── cat.jpg
│ ├── dog.png
│ └── dogs.gif
├── index.html
├── output.js
└── styles.css
├── readme.md
├── src
├── app
│ ├── App.js
│ └── components
│ │ ├── AstronomyCard.js
│ │ └── AstronomyContainer.js
├── assets
│ └── stylesheets
│ │ └── styles.scss
└── index.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015", "react"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Indrek Lasn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-2.0-from-scratch",
3 | "version": "2.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --progress",
8 | "start": "webpack --progress && webpack-dev-server -d --hot --config webpack.config.js --watch --progress",
9 | "production": "NODE_ENV=production webpack --progress"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "devDependencies": {
15 | "autoprefixer": "^7.1.1",
16 | "babel-core": "^6.24.1",
17 | "babel-loader": "^7.0.0",
18 | "babel-preset-es2015": "^6.24.1",
19 | "babel-preset-react": "^6.24.1",
20 | "css-hot-loader": "^1.0.4",
21 | "css-loader": "^0.28.0",
22 | "extract-text-webpack-plugin": "^2.1.0",
23 | "file-loader": "^0.11.1",
24 | "image-webpack-loader": "^3.3.0",
25 | "node-sass": "^4.5.2",
26 | "optimize-css-assets-webpack-plugin": "^1.3.1",
27 | "postcss-loader": "^2.0.5",
28 | "react": "^15.5.4",
29 | "react-dom": "^15.5.4",
30 | "sass-loader": "^6.0.3",
31 | "style-loader": "^0.16.1",
32 | "uglifyjs-webpack-plugin": "^0.4.3",
33 | "webpack": "^2.3.3",
34 | "webpack-dev-server": "^2.4.2"
35 | },
36 | "dependencies": {
37 | "axios": "^0.16.2"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer')
4 | ]
5 | }
--------------------------------------------------------------------------------
/public/images/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indreklasn/nasa-react-redux/552711d915086c2b1486bf7d4591c69e3b8f58a6/public/images/cat.jpg
--------------------------------------------------------------------------------
/public/images/dog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indreklasn/nasa-react-redux/552711d915086c2b1486bf7d4591c69e3b8f58a6/public/images/dog.png
--------------------------------------------------------------------------------
/public/images/dogs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/indreklasn/nasa-react-redux/552711d915086c2b1486bf7d4591c69e3b8f58a6/public/images/dogs.gif
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Webpack 2.0 from scratch!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/public/styles.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Merriweather);body {
2 | height: 100vh;
3 | background: #eaeaea;
4 | color: rgba(0, 0, 0, 0.87);
5 | font-size: 5rem;
6 | font-weight: 900;
7 | font-family: "Merriweather", sans-serif;
8 | padding: 0;
9 | margin: 0; }
10 |
11 | .astronomy-card {
12 | max-width: 75vw;
13 | margin: 50px auto;
14 | display: -webkit-box;
15 | display: -ms-flexbox;
16 | display: flex;
17 | background-color: #FFF;
18 | -webkit-box-orient: vertical;
19 | -webkit-box-direction: normal;
20 | -ms-flex-direction: column;
21 | flex-direction: column;
22 | -webkit-box-pack: center;
23 | -ms-flex-pack: center;
24 | justify-content: center;
25 | -webkit-box-align: center;
26 | -ms-flex-align: center;
27 | align-items: center;
28 | -webkit-box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
29 | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); }
30 | .astronomy-card .astronomy-title {
31 | margin: 25px 0;
32 | padding: 15px 45px;
33 | font-size: 18px;
34 | color: #6200ea; }
35 | .astronomy-card .astronomy-image-wrapper {
36 | padding: 10px; }
37 | .astronomy-card .astronomy-image-wrapper img {
38 | cursor: pointer;
39 | max-height: 500px;
40 | -webkit-filter: drop-shadow(6px 6px 12px rgba(0, 0, 0, 0.45));
41 | filter: drop-shadow(6px 6px 12px rgba(0, 0, 0, 0.45));
42 | -webkit-transition: all 325ms ease-in-out;
43 | transition: all 325ms ease-in-out; }
44 | .astronomy-card .astronomy-image-wrapper img:hover {
45 | -webkit-transition: all 325ms ease-in-out;
46 | transition: all 325ms ease-in-out;
47 | -webkit-transform: scale(1.07);
48 | transform: scale(1.07); }
49 | .astronomy-card p {
50 | font-size: 12px;
51 | padding: 10px 50px;
52 | letter-spacing: 0.66px;
53 | line-height: 2; }
54 | .astronomy-card span {
55 | font-size: 10px;
56 | color: #311b92;
57 | margin: 20px 0; }
58 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Learn How To Build: Astronomy Picture Of The Day App with NASA API and React + Redux
2 |
3 | ### Demo (image/video is different everyday!)
4 |
5 | 
6 |
7 | ## https://medium.com/@wesharehoodies/learn-how-to-build-astronomy-picture-of-the-day-app-with-nasa-api-and-react-redux-part-ii-83f15970d0e3
8 |
9 | ## How to start
10 |
11 | ```bash
12 | npm install
13 | ```
14 |
15 | ```
16 | npm run start
17 | ```
18 |
19 | ```
20 | npm run production
21 | ```
22 |
23 | ```
24 | npm run build
25 | ```
26 |
--------------------------------------------------------------------------------
/src/app/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import AstronomyContainer from './components/AstronomyContainer';
3 |
4 | const App = () => {
5 | return (
6 |
7 | )
8 | }
9 |
10 | export default App;
11 |
--------------------------------------------------------------------------------
/src/app/components/AstronomyCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const AstronomyCard = (props) => {
4 |
5 | const { title,
6 | url,
7 | hdurl,
8 | explanation,
9 | date,
10 | copyright,
11 | media_type
12 | } = props.data;
13 |
14 | function renderContent() {
15 | switch(media_type) {
16 |
17 | case('video'):
18 | return (
19 |
26 | )
27 |
28 | case('image'):
29 | return (
30 |
31 |
32 |
33 | )
34 |
35 | default:
36 | return null
37 | }
38 | }
39 |
40 | return (
41 |
42 |
43 |
{title}
44 |
45 | {renderContent()}
46 |
47 |
{explanation}
48 |
49 |
{date}, {copyright}
50 |
51 |
52 | )
53 | }
54 |
55 | export default AstronomyCard;
--------------------------------------------------------------------------------
/src/app/components/AstronomyContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import AstronomyCard from './AstronomyCard';
3 | import axios from 'axios';
4 |
5 | class AstronomyContainer extends Component {
6 |
7 | constructor() {
8 | super();
9 |
10 | this.state = {
11 | astronomy: []
12 | }
13 |
14 | }
15 |
16 | componentDidMount() {
17 | const API_KEY = 'nxKl8yTvpvsXEqRz06mTPnn29uyckFmFCYrnqEIz';
18 | const END_POINT = 'https://api.nasa.gov/planetary/apod?api_key='
19 |
20 | axios.get(END_POINT+API_KEY)
21 | .then(response => {
22 |
23 | this.setState({
24 | astronomy: response.data
25 | })
26 |
27 | })
28 | .catch(error => {
29 | console.log(error, 'failed to fetch data')
30 | });
31 | }
32 |
33 | render() {
34 | const { astronomy } = this.state;
35 | return (
36 |
37 | )
38 | }
39 | }
40 |
41 | export default AstronomyContainer;
--------------------------------------------------------------------------------
/src/assets/stylesheets/styles.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Merriweather');
2 |
3 |
4 | $brand-purple: rgb(135,140,223);
5 | $brand-green: rgb(153,251,198);
6 | $font-size: 5rem;
7 | $merriweather: "Merriweather", sans-serif;
8 |
9 | body {
10 | height: 100vh;
11 | background: #eaeaea;
12 | color: rgba(0, 0, 0, 0.87);
13 | font-size: $font-size;
14 | font-weight: 900;
15 | font-family: $merriweather;
16 | padding: 0;
17 | margin: 0;
18 | }
19 |
20 |
21 | .astronomy-card {
22 | max-width: 75vw;
23 | margin: 50px auto;
24 | display: flex;
25 | background-color: #FFF;
26 | flex-direction: column;
27 | justify-content: center;
28 | align-items: center;
29 | box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
30 |
31 | .astronomy-title {
32 | margin: 25px 0;
33 | padding: 15px 45px;
34 | font-size: 18px;
35 | color: #6200ea;
36 | }
37 |
38 | .astronomy-image-wrapper {
39 | padding: 10px;
40 |
41 | img {
42 | cursor: pointer;
43 | max-height: 500px;
44 | filter: drop-shadow(6px 6px 12px rgba(0,0,0,0.45));
45 | transition: all 325ms ease-in-out;
46 | &:hover {
47 | transition: all 325ms ease-in-out;
48 | transform: scale(1.07);
49 | }
50 | }
51 | }
52 |
53 | p {
54 | font-size: 12px;
55 | padding: 10px 50px;
56 | letter-spacing: 0.66px;
57 | line-height: 2;
58 | }
59 |
60 | span {
61 | font-size: 10px;
62 | color: #311b92;
63 | margin: 20px 0;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'; // import the main react dependency
2 | import ReactDOM from 'react-dom'; // import reactDOM
3 | import App from './app/App'; // import the main app component
4 |
5 | import './assets/stylesheets/styles.scss';
6 |
7 | ReactDOM.render(
8 | , // render our App component
9 | document.getElementById('root') // and mount it to our #root element
10 | );
11 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack'); // webpack itself
2 | const path = require('path'); // nodejs dependency when dealing with paths
3 | const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'); // require webpack plugin
4 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); // require webpack plugin
5 | const OptimizeCSSAssets = require('optimize-css-assets-webpack-plugin'); // require webpack plugin
6 |
7 | let config = { // config object
8 | entry: './src/index.js', // entry file
9 | output: { // output
10 | path: path.resolve(__dirname, 'public'), // ouput path
11 | filename: 'output.js' // output filename
12 | },
13 | resolve: { // These options change how modules are resolved
14 | extensions: ['.js', '.jsx', '.json', '.scss', '.css', '.jpeg', '.jpg', '.gif', '.png'], // Automatically resolve certain extensions
15 | alias: { // Create aliases
16 | images: path.resolve(__dirname, 'src/assets/images') // src/assets/images alias
17 | }
18 | },
19 | module: {
20 | rules: [ // loader rules
21 | {
22 | test: /\.js$/, // files ending with .js
23 | exclude: /node_modules/, // exclude the node_modules directory
24 | loader: 'babel-loader' // use this (babel-core) loader
25 | },
26 | {
27 | test: /\.scss$/, // files ending with .scss
28 | use: ['css-hot-loader'].concat(ExtractTextWebpackPlugin.extract({ // HMR for styles
29 | fallback: 'style-loader',
30 | use: ['css-loader', 'sass-loader', 'postcss-loader'],
31 | })),
32 | },
33 | {
34 | test: /\.jsx$/, // all files ending with .jsx
35 | loader: 'babel-loader', // use the babel-loader for all .jsx files
36 | exclude: /node_modules/ // exclude searching for files in the node_modules directory
37 | },
38 | {
39 | test: /\.(jpe?g|png|gif|svg)$/i,
40 | loaders: ['file-loader?context=src/assets/images/&name=images/[path][name].[ext]', { // images loader
41 | loader: 'image-webpack-loader',
42 | query: {
43 | mozjpeg: {
44 | progressive: true,
45 | },
46 | gifsicle: {
47 | interlaced: false,
48 | },
49 | optipng: {
50 | optimizationLevel: 4,
51 | },
52 | pngquant: {
53 | quality: '75-90',
54 | speed: 3,
55 | },
56 | },
57 | }],
58 | exclude: /node_modules/,
59 | include: __dirname,
60 | },
61 | ] // end rules
62 | },
63 | plugins: [ // webpack plugins
64 | new ExtractTextWebpackPlugin('styles.css'), // call the ExtractTextWebpackPlugin constructor and name our css file
65 | ],
66 | devServer: {
67 | contentBase: path.resolve(__dirname, 'public'), // A directory or URL to serve HTML content from.
68 | historyApiFallback: true, // fallback to /index.html for Single Page Applications.
69 | inline: true, // inline mode (set to false to disable including client scripts (like livereload)
70 | open: true, // open default browser while launching
71 | compress: true, // Enable gzip compression for everything served:
72 | hot: true // Enable webpack's Hot Module Replacement feature
73 | },
74 | devtool: 'eval-source-map', // enable devtool for better debugging experience
75 | }
76 |
77 | module.exports = config;
78 |
79 | if (process.env.NODE_ENV === 'production') { // if we're in production mode, here's what happens next
80 | module.exports.plugins.push(
81 | new webpack.optimize.UglifyJsPlugin(), // call the uglify plugin
82 | new OptimizeCSSAssets() // call the css optimizer (minfication)
83 | );
84 | }
85 |
--------------------------------------------------------------------------------