├── .babelrc ├── .github └── main.workflow ├── .gitignore ├── .tool-versions ├── CNAME ├── LICENSE ├── README.md ├── node.api.js ├── package.json ├── public └── robots.txt ├── script ├── create-newsletter ├── first-time-contributors └── recreate-all ├── src ├── App.js ├── containers │ ├── 404.js │ ├── App.css │ ├── Issue.js │ ├── Layout.js │ └── SubscribeForm.js ├── email-template.mjml ├── images │ ├── favicon.png │ ├── logo-with-bg.jpg │ ├── logo.png │ ├── telegram.svg │ ├── twitter-card.png │ └── twitter.svg ├── index-template.mjml ├── index.js ├── issues │ ├── 1 │ │ ├── README.md │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 2 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 3 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 4 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 5 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 6 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 7 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 8 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 9 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 10 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 11 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 12 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 13 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 14 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 15 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 16 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 17 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 18 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 19 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 20 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── first-time-contributors.txt │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 21 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── first-time-contributors.txt │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 22 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── first-time-contributors.txt │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 23 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── first-time-contributors.txt │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 24 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── first-time-contributors.txt │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 25 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 26 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 27 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 28 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 29 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 30 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 31 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 32 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 33 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 34 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 35 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 36 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 37 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 38 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 39 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 40 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 41 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ ├── 42 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter-card.png │ └── 43 │ │ ├── README.md │ │ ├── TWITTER.md │ │ ├── index.html │ │ ├── issue.png │ │ └── twitter.png ├── known-authors.json └── util │ └── clicky.js ├── static.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-static/.babelrc" 3 | } 4 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Build and Deploy" { 2 | on = "push" 3 | resolves = ["Deploy"] 4 | } 5 | 6 | action "Install" { 7 | uses = "nuxt/actions-yarn@master" 8 | args = "install" 9 | } 10 | 11 | action "Build" { 12 | needs = "Install" 13 | uses = "nuxt/actions-yarn@master" 14 | args = "build" 15 | } 16 | 17 | action "Filter" { 18 | uses = "actions/bin/filter@master" 19 | needs = ["Build"] 20 | args = "branch master" 21 | } 22 | 23 | action "Deploy" { 24 | needs = "Filter" 25 | uses = "maxheld83/ghpages@v0.2.1" 26 | env = { 27 | BUILD_DIR = "dist/" 28 | } 29 | secrets = ["GH_PAT"] 30 | } 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | src/issues/**/*.html 3 | !src/issues/**/index.html 4 | 5 | /coverage 6 | 7 | # production 8 | /dist 9 | /tmp 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | node 16 2 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | this-week-in-react.org -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Philipp Spieß 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![This Week in React ⚛️](http://cl.ly/f88f980bd8bb/twitter-card.png) 2 | 3 | # This Week in React ️️⚛️ 4 | 5 | This repository contains the website and email templates for This Week in React ⚛️ a newsletter that covers React Core and React DOM. 6 | 7 | ## Contributing 8 | 9 | Every help on this project is greatly appreciated. To get you started, here's a quick guide on how to make good and clean pull-requests: 10 | 11 | 1. Create a fork of this [repository](https://github.com/philipp-spiess/this-week-in-react), so you can work on your own environment. 12 | 2. Install development dependencies locally: 13 | 14 | ```bash 15 | git clone git@github.com:/this-week-in-react.git 16 | cd this-week-in-react 17 | yarn install 18 | ``` 19 | 20 | 3. Make changes using your favorite editor. 21 | 4. Commit your changes ([here](https://chris.beams.io/posts/git-commit/) is a wonderful guide on how to make amazing git commits). 22 | 5. After a few seconds, a button to create a pull request should be visible inside the [Pull requests](https://github.com/philipp-spiess/this-week-in-react/pulls) section. 23 | 24 | ## License 25 | 26 | [MIT](https://github.com/philipp-spiess/this-week-in-react/blob/master/README.md) 27 | -------------------------------------------------------------------------------- /node.api.js: -------------------------------------------------------------------------------- 1 | export default pluginOptions => ({ 2 | webpack: config => { 3 | const oneOf = config.module.rules[0].oneOf 4 | 5 | oneOf.unshift( 6 | { 7 | test: /\.(html)$/, 8 | use: { 9 | loader: 'html-loader', 10 | options: { 11 | minimize: true, 12 | } 13 | } 14 | } 15 | ) 16 | 17 | return config 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "this-week-in-react", 3 | "version": "0.0.1", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "react-static start", 8 | "stage": "react-static build --staging", 9 | "build": "react-static build && echo 'this-week-in-react.org' > dist/CNAME", 10 | "serve": "serve dist -p 3000", 11 | "format": "prettier {{src,script}/**/*.{js,css},*.md} --write", 12 | "predeploy": "npm run build", 13 | "deploy": "gh-pages -d dist" 14 | }, 15 | "dependencies": { 16 | "@reach/router": "^1.2.1", 17 | "promise-parallel-throttle": "^3.3.0", 18 | "react": "^16.8.0-alpha.1", 19 | "react-dom": "^16.8.0-alpha.1", 20 | "react-helmet": "^5.2.0", 21 | "react-hot-loader": "^4.5.3", 22 | "react-mailchimp-subscribe": "^2.1.0", 23 | "react-router": "^4.2.0", 24 | "react-router-dom": "^4.3.1", 25 | "react-static": "6.3.3" 26 | }, 27 | "devDependencies": { 28 | "@octokit/rest": "^16.13.3", 29 | "gh-pages": "^2.0.1", 30 | "glob": "^7.1.3", 31 | "html-loader": "^0.5.5", 32 | "markdown-it": "^8.4.2", 33 | "mjml": "^4.3.1", 34 | "open-graph-scraper": "^3.6.0", 35 | "prettier": "^1.16.1", 36 | "serve": "^10.1.1", 37 | "truncate": "^2.0.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | -------------------------------------------------------------------------------- /script/recreate-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./script/create-newsletter 20 "15 Feb 2019" 4 | ./script/create-newsletter 19 "8 Feb 2019" 5 | ./script/create-newsletter 18 "1 Feb 2019" 6 | ./script/create-newsletter 17 "25 Jan 2019" 7 | ./script/create-newsletter 16 "18 Jan 2019" 8 | ./script/create-newsletter 15 "11 Jan 2019" 9 | ./script/create-newsletter 14 "21 Dec 2018" 10 | ./script/create-newsletter 13 "14 Dec 2018" 11 | ./script/create-newsletter 12 "7 Dec 2018" 12 | ./script/create-newsletter 11 "30 Nov 2018" 13 | ./script/create-newsletter 10 "23 Nov 2018" 14 | ./script/create-newsletter 9 "16 Nov 2018" 15 | ./script/create-newsletter 8 "9 Nov 2018" 16 | ./script/create-newsletter 7 "2 Nov 2018" 17 | ./script/create-newsletter 6 "26 Oct 2018" 18 | ./script/create-newsletter 5 "19 Oct 2018" 19 | ./script/create-newsletter 4 "12 Oct 2018" 20 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Root, Routes } from 'react-static' 3 | 4 | const App = () => ( 5 | 6 |
7 | 8 |
9 |
10 | ) 11 | 12 | export default App 13 | -------------------------------------------------------------------------------- /src/containers/404.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Layout from "./Layout"; 3 | 4 | export default () => ( 5 | 6 |
7 | 404 – Oh no! 8 |

Is anything missing? Ping me on Twitter.

9 |
10 |
11 | ); 12 | -------------------------------------------------------------------------------- /src/containers/Issue.js: -------------------------------------------------------------------------------- 1 | import { Helmet } from "react-helmet"; 2 | import { Link } from "@reach/router"; 3 | import { withRouteData } from "react-static"; 4 | import Layout from "./Layout"; 5 | import React from "react"; 6 | 7 | function Issue(props) { 8 | return ( 9 | 10 | 11 | {`This Week in React – Issue ${props.issue}`} 12 | 13 |
14 |
15 |

Issue {props.issue}

16 |

21 |

22 |
23 | 36 |
37 | 38 | 39 | ); 40 | } 41 | 42 | class Preview extends React.Component { 43 | state = { height: 800 }; 44 | ref = React.createRef(); 45 | componentDidMount() { 46 | const frame = this.ref.current; 47 | const frameDocument = frame.contentDocument; 48 | 49 | const update = () => 50 | this.setState({ height: frameDocument.body.offsetHeight + 30 }); 51 | 52 | frame.onload = () => { 53 | frame.contentWindow.onresize = () => update(); 54 | update(); 55 | }; 56 | 57 | frameDocument.open(); 58 | frameDocument.write(this.props.html); 59 | frameDocument.close(); 60 | } 61 | render() { 62 | return