diff --git a/code/01-starting-setup/package.json b/code/01-starting-setup/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/01-starting-setup/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/01-starting-setup/public/favicon.ico b/code/01-starting-setup/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/01-starting-setup/public/favicon.ico differ
diff --git a/code/01-starting-setup/public/index.html b/code/01-starting-setup/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/01-starting-setup/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/01-starting-setup/public/logo192.png b/code/01-starting-setup/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/01-starting-setup/public/logo192.png differ
diff --git a/code/01-starting-setup/public/logo512.png b/code/01-starting-setup/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/01-starting-setup/public/logo512.png differ
diff --git a/code/01-starting-setup/public/manifest.json b/code/01-starting-setup/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/01-starting-setup/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/01-starting-setup/public/robots.txt b/code/01-starting-setup/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/01-starting-setup/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/01-starting-setup/src/App.js b/code/01-starting-setup/src/App.js
new file mode 100644
index 0000000000..4a194e6079
--- /dev/null
+++ b/code/01-starting-setup/src/App.js
@@ -0,0 +1,9 @@
+function App() {
+ return (
+
+
Let's get started!
+
+ );
+}
+
+export default App;
diff --git a/code/01-starting-setup/src/index.css b/code/01-starting-setup/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/01-starting-setup/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/01-starting-setup/src/index.js b/code/01-starting-setup/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/01-starting-setup/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/02-building-a-first-custom-component/package.json b/code/02-building-a-first-custom-component/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/02-building-a-first-custom-component/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/02-building-a-first-custom-component/public/favicon.ico b/code/02-building-a-first-custom-component/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/02-building-a-first-custom-component/public/favicon.ico differ
diff --git a/code/02-building-a-first-custom-component/public/index.html b/code/02-building-a-first-custom-component/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/02-building-a-first-custom-component/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/02-building-a-first-custom-component/public/logo192.png b/code/02-building-a-first-custom-component/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/02-building-a-first-custom-component/public/logo192.png differ
diff --git a/code/02-building-a-first-custom-component/public/logo512.png b/code/02-building-a-first-custom-component/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/02-building-a-first-custom-component/public/logo512.png differ
diff --git a/code/02-building-a-first-custom-component/public/manifest.json b/code/02-building-a-first-custom-component/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/02-building-a-first-custom-component/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/02-building-a-first-custom-component/public/robots.txt b/code/02-building-a-first-custom-component/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/02-building-a-first-custom-component/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/02-building-a-first-custom-component/src/App.js b/code/02-building-a-first-custom-component/src/App.js
new file mode 100644
index 0000000000..264e51e726
--- /dev/null
+++ b/code/02-building-a-first-custom-component/src/App.js
@@ -0,0 +1,12 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/02-building-a-first-custom-component/src/components/ExpenseItem.js b/code/02-building-a-first-custom-component/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..790588b878
--- /dev/null
+++ b/code/02-building-a-first-custom-component/src/components/ExpenseItem.js
@@ -0,0 +1,5 @@
+function ExpenseItem() {
+ return Expense item!
;
+}
+
+export default ExpenseItem;
diff --git a/code/02-building-a-first-custom-component/src/index.css b/code/02-building-a-first-custom-component/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/02-building-a-first-custom-component/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/02-building-a-first-custom-component/src/index.js b/code/02-building-a-first-custom-component/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/02-building-a-first-custom-component/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/03-writing-more-complex-jsx-code/package.json b/code/03-writing-more-complex-jsx-code/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/03-writing-more-complex-jsx-code/public/favicon.ico b/code/03-writing-more-complex-jsx-code/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/03-writing-more-complex-jsx-code/public/favicon.ico differ
diff --git a/code/03-writing-more-complex-jsx-code/public/index.html b/code/03-writing-more-complex-jsx-code/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/03-writing-more-complex-jsx-code/public/logo192.png b/code/03-writing-more-complex-jsx-code/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/03-writing-more-complex-jsx-code/public/logo192.png differ
diff --git a/code/03-writing-more-complex-jsx-code/public/logo512.png b/code/03-writing-more-complex-jsx-code/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/03-writing-more-complex-jsx-code/public/logo512.png differ
diff --git a/code/03-writing-more-complex-jsx-code/public/manifest.json b/code/03-writing-more-complex-jsx-code/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/03-writing-more-complex-jsx-code/public/robots.txt b/code/03-writing-more-complex-jsx-code/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/03-writing-more-complex-jsx-code/src/App.js b/code/03-writing-more-complex-jsx-code/src/App.js
new file mode 100644
index 0000000000..264e51e726
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/src/App.js
@@ -0,0 +1,12 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/03-writing-more-complex-jsx-code/src/components/ExpenseItem.js b/code/03-writing-more-complex-jsx-code/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..1b178e39c5
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/src/components/ExpenseItem.js
@@ -0,0 +1,13 @@
+function ExpenseItem() {
+ return (
+
+
March 28th 2021
+
+
Car Insurance
+
$294.67
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/03-writing-more-complex-jsx-code/src/index.css b/code/03-writing-more-complex-jsx-code/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/03-writing-more-complex-jsx-code/src/index.js b/code/03-writing-more-complex-jsx-code/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/03-writing-more-complex-jsx-code/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/04-adding-basic-css-styling/package.json b/code/04-adding-basic-css-styling/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/04-adding-basic-css-styling/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/04-adding-basic-css-styling/public/favicon.ico b/code/04-adding-basic-css-styling/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/04-adding-basic-css-styling/public/favicon.ico differ
diff --git a/code/04-adding-basic-css-styling/public/index.html b/code/04-adding-basic-css-styling/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/04-adding-basic-css-styling/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/04-adding-basic-css-styling/public/logo192.png b/code/04-adding-basic-css-styling/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/04-adding-basic-css-styling/public/logo192.png differ
diff --git a/code/04-adding-basic-css-styling/public/logo512.png b/code/04-adding-basic-css-styling/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/04-adding-basic-css-styling/public/logo512.png differ
diff --git a/code/04-adding-basic-css-styling/public/manifest.json b/code/04-adding-basic-css-styling/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/04-adding-basic-css-styling/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/04-adding-basic-css-styling/public/robots.txt b/code/04-adding-basic-css-styling/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/04-adding-basic-css-styling/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/04-adding-basic-css-styling/src/App.js b/code/04-adding-basic-css-styling/src/App.js
new file mode 100644
index 0000000000..264e51e726
--- /dev/null
+++ b/code/04-adding-basic-css-styling/src/App.js
@@ -0,0 +1,12 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/04-adding-basic-css-styling/src/components/ExpenseItem.css b/code/04-adding-basic-css-styling/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/04-adding-basic-css-styling/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/04-adding-basic-css-styling/src/components/ExpenseItem.js b/code/04-adding-basic-css-styling/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..4ed06c3ff8
--- /dev/null
+++ b/code/04-adding-basic-css-styling/src/components/ExpenseItem.js
@@ -0,0 +1,15 @@
+import './ExpenseItem.css';
+
+function ExpenseItem() {
+ return (
+
+
March 28th 2021
+
+
Car Insurance
+
$294.67
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/04-adding-basic-css-styling/src/index.css b/code/04-adding-basic-css-styling/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/04-adding-basic-css-styling/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/04-adding-basic-css-styling/src/index.js b/code/04-adding-basic-css-styling/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/04-adding-basic-css-styling/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/05-outputting-dynamic-data/package.json b/code/05-outputting-dynamic-data/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/05-outputting-dynamic-data/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/05-outputting-dynamic-data/public/favicon.ico b/code/05-outputting-dynamic-data/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/05-outputting-dynamic-data/public/favicon.ico differ
diff --git a/code/05-outputting-dynamic-data/public/index.html b/code/05-outputting-dynamic-data/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/05-outputting-dynamic-data/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/05-outputting-dynamic-data/public/logo192.png b/code/05-outputting-dynamic-data/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/05-outputting-dynamic-data/public/logo192.png differ
diff --git a/code/05-outputting-dynamic-data/public/logo512.png b/code/05-outputting-dynamic-data/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/05-outputting-dynamic-data/public/logo512.png differ
diff --git a/code/05-outputting-dynamic-data/public/manifest.json b/code/05-outputting-dynamic-data/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/05-outputting-dynamic-data/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/05-outputting-dynamic-data/public/robots.txt b/code/05-outputting-dynamic-data/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/05-outputting-dynamic-data/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/05-outputting-dynamic-data/src/App.js b/code/05-outputting-dynamic-data/src/App.js
new file mode 100644
index 0000000000..264e51e726
--- /dev/null
+++ b/code/05-outputting-dynamic-data/src/App.js
@@ -0,0 +1,12 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/05-outputting-dynamic-data/src/components/ExpenseItem.css b/code/05-outputting-dynamic-data/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/05-outputting-dynamic-data/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/05-outputting-dynamic-data/src/components/ExpenseItem.js b/code/05-outputting-dynamic-data/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..362371a920
--- /dev/null
+++ b/code/05-outputting-dynamic-data/src/components/ExpenseItem.js
@@ -0,0 +1,19 @@
+import './ExpenseItem.css';
+
+function ExpenseItem() {
+ const expenseDate = new Date(2021, 2, 28);
+ const expenseTitle = 'Car Insurance';
+ const expenseAmount = 294.67;
+
+ return (
+
+
{expenseDate.toISOString()}
+
+
{expenseTitle}
+
${expenseAmount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/05-outputting-dynamic-data/src/index.css b/code/05-outputting-dynamic-data/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/05-outputting-dynamic-data/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/05-outputting-dynamic-data/src/index.js b/code/05-outputting-dynamic-data/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/05-outputting-dynamic-data/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/06-passing-data-via-props/package.json b/code/06-passing-data-via-props/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/06-passing-data-via-props/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/06-passing-data-via-props/public/favicon.ico b/code/06-passing-data-via-props/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/06-passing-data-via-props/public/favicon.ico differ
diff --git a/code/06-passing-data-via-props/public/index.html b/code/06-passing-data-via-props/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/06-passing-data-via-props/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/06-passing-data-via-props/public/logo192.png b/code/06-passing-data-via-props/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/06-passing-data-via-props/public/logo192.png differ
diff --git a/code/06-passing-data-via-props/public/logo512.png b/code/06-passing-data-via-props/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/06-passing-data-via-props/public/logo512.png differ
diff --git a/code/06-passing-data-via-props/public/manifest.json b/code/06-passing-data-via-props/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/06-passing-data-via-props/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/06-passing-data-via-props/public/robots.txt b/code/06-passing-data-via-props/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/06-passing-data-via-props/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/06-passing-data-via-props/src/App.js b/code/06-passing-data-via-props/src/App.js
new file mode 100644
index 0000000000..878e1cd3a3
--- /dev/null
+++ b/code/06-passing-data-via-props/src/App.js
@@ -0,0 +1,53 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ return (
+
+
Let's get started!
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/code/06-passing-data-via-props/src/components/ExpenseItem.css b/code/06-passing-data-via-props/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/06-passing-data-via-props/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/06-passing-data-via-props/src/components/ExpenseItem.js b/code/06-passing-data-via-props/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..9de60d6b21
--- /dev/null
+++ b/code/06-passing-data-via-props/src/components/ExpenseItem.js
@@ -0,0 +1,15 @@
+import './ExpenseItem.css';
+
+function ExpenseItem(props) {
+ return (
+
+
{props.date.toISOString()}
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/06-passing-data-via-props/src/index.css b/code/06-passing-data-via-props/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/06-passing-data-via-props/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/06-passing-data-via-props/src/index.js b/code/06-passing-data-via-props/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/06-passing-data-via-props/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/07-adding-normal-javascript-logic/package.json b/code/07-adding-normal-javascript-logic/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/07-adding-normal-javascript-logic/public/favicon.ico b/code/07-adding-normal-javascript-logic/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/07-adding-normal-javascript-logic/public/favicon.ico differ
diff --git a/code/07-adding-normal-javascript-logic/public/index.html b/code/07-adding-normal-javascript-logic/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/07-adding-normal-javascript-logic/public/logo192.png b/code/07-adding-normal-javascript-logic/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/07-adding-normal-javascript-logic/public/logo192.png differ
diff --git a/code/07-adding-normal-javascript-logic/public/logo512.png b/code/07-adding-normal-javascript-logic/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/07-adding-normal-javascript-logic/public/logo512.png differ
diff --git a/code/07-adding-normal-javascript-logic/public/manifest.json b/code/07-adding-normal-javascript-logic/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/07-adding-normal-javascript-logic/public/robots.txt b/code/07-adding-normal-javascript-logic/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/07-adding-normal-javascript-logic/src/App.js b/code/07-adding-normal-javascript-logic/src/App.js
new file mode 100644
index 0000000000..878e1cd3a3
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/src/App.js
@@ -0,0 +1,53 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ return (
+
+
Let's get started!
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.css b/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.js b/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..6821b40063
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/src/components/ExpenseItem.js
@@ -0,0 +1,23 @@
+import './ExpenseItem.css';
+
+function ExpenseItem(props) {
+ const month = props.date.toLocaleString('en-US', { month: 'long' });
+ const day = props.date.toLocaleString('en-US', { day: '2-digit' });
+ const year = props.date.getFullYear();
+
+ return (
+
+
+
{month}
+
{year}
+
{day}
+
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/07-adding-normal-javascript-logic/src/index.css b/code/07-adding-normal-javascript-logic/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/07-adding-normal-javascript-logic/src/index.js b/code/07-adding-normal-javascript-logic/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/07-adding-normal-javascript-logic/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/08-splitting-components-into-multiple-components/package.json b/code/08-splitting-components-into-multiple-components/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/08-splitting-components-into-multiple-components/public/favicon.ico b/code/08-splitting-components-into-multiple-components/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/08-splitting-components-into-multiple-components/public/favicon.ico differ
diff --git a/code/08-splitting-components-into-multiple-components/public/index.html b/code/08-splitting-components-into-multiple-components/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/08-splitting-components-into-multiple-components/public/logo192.png b/code/08-splitting-components-into-multiple-components/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/08-splitting-components-into-multiple-components/public/logo192.png differ
diff --git a/code/08-splitting-components-into-multiple-components/public/logo512.png b/code/08-splitting-components-into-multiple-components/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/08-splitting-components-into-multiple-components/public/logo512.png differ
diff --git a/code/08-splitting-components-into-multiple-components/public/manifest.json b/code/08-splitting-components-into-multiple-components/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/08-splitting-components-into-multiple-components/public/robots.txt b/code/08-splitting-components-into-multiple-components/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/08-splitting-components-into-multiple-components/src/App.js b/code/08-splitting-components-into-multiple-components/src/App.js
new file mode 100644
index 0000000000..f88ab5fa92
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/App.js
@@ -0,0 +1,53 @@
+import ExpenseItem from './components/ExpenseItem';
+
+function App() {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ return (
+
+
Let's get started!
+
+
+
+
+
+ );
+}
+
+export default App;
diff --git a/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.css b/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.css
new file mode 100644
index 0000000000..d69691de84
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.css
@@ -0,0 +1,26 @@
+.expense-date {
+ display: flex;
+ flex-direction: column;
+ width: 5.5rem;
+ height: 5.5rem;
+ border: 1px solid #ececec;
+ background-color: #2a2a2a;
+ color: white;
+ border-radius: 12px;
+ align-items: center;
+ justify-content: center;
+}
+
+.expense-date__month {
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.expense-date__year {
+ font-size: 0.75rem;
+}
+
+.expense-date__day {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
diff --git a/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.js b/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.js
new file mode 100644
index 0000000000..ba5698cf0d
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/components/ExpenseDate.js
@@ -0,0 +1,17 @@
+import './ExpenseDate.css';
+
+function ExpenseDate(props) {
+ const month = props.date.toLocaleString('en-US', { month: 'long' });
+ const day = props.date.toLocaleString('en-US', { day: '2-digit' });
+ const year = props.date.getFullYear();
+
+ return (
+
+
{month}
+
{year}
+
{day}
+
+ );
+}
+
+export default ExpenseDate;
diff --git a/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.css b/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.js b/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..07e4e0f98a
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/components/ExpenseItem.js
@@ -0,0 +1,16 @@
+import ExpenseDate from './ExpenseDate';
+import './ExpenseItem.css';
+
+function ExpenseItem(props) {
+ return (
+
+
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/08-splitting-components-into-multiple-components/src/index.css b/code/08-splitting-components-into-multiple-components/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/08-splitting-components-into-multiple-components/src/index.js b/code/08-splitting-components-into-multiple-components/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/08-splitting-components-into-multiple-components/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/09-assignment-1-solution/package.json b/code/09-assignment-1-solution/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/09-assignment-1-solution/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/09-assignment-1-solution/public/favicon.ico b/code/09-assignment-1-solution/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/09-assignment-1-solution/public/favicon.ico differ
diff --git a/code/09-assignment-1-solution/public/index.html b/code/09-assignment-1-solution/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/09-assignment-1-solution/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/09-assignment-1-solution/public/logo192.png b/code/09-assignment-1-solution/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/09-assignment-1-solution/public/logo192.png differ
diff --git a/code/09-assignment-1-solution/public/logo512.png b/code/09-assignment-1-solution/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/09-assignment-1-solution/public/logo512.png differ
diff --git a/code/09-assignment-1-solution/public/manifest.json b/code/09-assignment-1-solution/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/09-assignment-1-solution/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/09-assignment-1-solution/public/robots.txt b/code/09-assignment-1-solution/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/09-assignment-1-solution/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/09-assignment-1-solution/src/App.js b/code/09-assignment-1-solution/src/App.js
new file mode 100644
index 0000000000..21dfc576bc
--- /dev/null
+++ b/code/09-assignment-1-solution/src/App.js
@@ -0,0 +1,34 @@
+import Expenses from './components/Expenses';
+
+function App() {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/09-assignment-1-solution/src/components/ExpenseDate.css b/code/09-assignment-1-solution/src/components/ExpenseDate.css
new file mode 100644
index 0000000000..d69691de84
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/ExpenseDate.css
@@ -0,0 +1,26 @@
+.expense-date {
+ display: flex;
+ flex-direction: column;
+ width: 5.5rem;
+ height: 5.5rem;
+ border: 1px solid #ececec;
+ background-color: #2a2a2a;
+ color: white;
+ border-radius: 12px;
+ align-items: center;
+ justify-content: center;
+}
+
+.expense-date__month {
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.expense-date__year {
+ font-size: 0.75rem;
+}
+
+.expense-date__day {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
diff --git a/code/09-assignment-1-solution/src/components/ExpenseDate.js b/code/09-assignment-1-solution/src/components/ExpenseDate.js
new file mode 100644
index 0000000000..ba5698cf0d
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/ExpenseDate.js
@@ -0,0 +1,17 @@
+import './ExpenseDate.css';
+
+function ExpenseDate(props) {
+ const month = props.date.toLocaleString('en-US', { month: 'long' });
+ const day = props.date.toLocaleString('en-US', { day: '2-digit' });
+ const year = props.date.getFullYear();
+
+ return (
+
+
{month}
+
{year}
+
{day}
+
+ );
+}
+
+export default ExpenseDate;
diff --git a/code/09-assignment-1-solution/src/components/ExpenseItem.css b/code/09-assignment-1-solution/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/09-assignment-1-solution/src/components/ExpenseItem.js b/code/09-assignment-1-solution/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..07e4e0f98a
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/ExpenseItem.js
@@ -0,0 +1,16 @@
+import ExpenseDate from './ExpenseDate';
+import './ExpenseItem.css';
+
+function ExpenseItem(props) {
+ return (
+
+
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/09-assignment-1-solution/src/components/Expenses.css b/code/09-assignment-1-solution/src/components/Expenses.css
new file mode 100644
index 0000000000..2a3c9d0fbd
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/Expenses.css
@@ -0,0 +1,9 @@
+.expenses {
+ padding: 1rem;
+ background-color: rgb(31, 31, 31);
+ margin: 2rem auto;
+ width: 50rem;
+ max-width: 95%;
+ border-radius: 12px;
+ box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
+}
diff --git a/code/09-assignment-1-solution/src/components/Expenses.js b/code/09-assignment-1-solution/src/components/Expenses.js
new file mode 100644
index 0000000000..6bd58d5710
--- /dev/null
+++ b/code/09-assignment-1-solution/src/components/Expenses.js
@@ -0,0 +1,31 @@
+import ExpenseItem from './ExpenseItem';
+import './Expenses.css';
+
+function Expenses(props) {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default Expenses;
diff --git a/code/09-assignment-1-solution/src/index.css b/code/09-assignment-1-solution/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/09-assignment-1-solution/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/09-assignment-1-solution/src/index.js b/code/09-assignment-1-solution/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/09-assignment-1-solution/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/10-the-concept-of-composition/package.json b/code/10-the-concept-of-composition/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/10-the-concept-of-composition/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/10-the-concept-of-composition/public/favicon.ico b/code/10-the-concept-of-composition/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/10-the-concept-of-composition/public/favicon.ico differ
diff --git a/code/10-the-concept-of-composition/public/index.html b/code/10-the-concept-of-composition/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/10-the-concept-of-composition/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/10-the-concept-of-composition/public/logo192.png b/code/10-the-concept-of-composition/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/10-the-concept-of-composition/public/logo192.png differ
diff --git a/code/10-the-concept-of-composition/public/logo512.png b/code/10-the-concept-of-composition/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/10-the-concept-of-composition/public/logo512.png differ
diff --git a/code/10-the-concept-of-composition/public/manifest.json b/code/10-the-concept-of-composition/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/10-the-concept-of-composition/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/10-the-concept-of-composition/public/robots.txt b/code/10-the-concept-of-composition/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/10-the-concept-of-composition/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/10-the-concept-of-composition/src/App.js b/code/10-the-concept-of-composition/src/App.js
new file mode 100644
index 0000000000..21dfc576bc
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/App.js
@@ -0,0 +1,34 @@
+import Expenses from './components/Expenses';
+
+function App() {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/10-the-concept-of-composition/src/components/Card.css b/code/10-the-concept-of-composition/src/components/Card.css
new file mode 100644
index 0000000000..166cffe458
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/Card.css
@@ -0,0 +1,4 @@
+.card {
+ border-radius: 12px;
+ box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
+}
diff --git a/code/10-the-concept-of-composition/src/components/Card.js b/code/10-the-concept-of-composition/src/components/Card.js
new file mode 100644
index 0000000000..2615acdd3c
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/Card.js
@@ -0,0 +1,9 @@
+import './Card.css';
+
+function Card(props) {
+ const classes = 'card ' + props.className;
+
+ return {props.children}
;
+}
+
+export default Card;
diff --git a/code/10-the-concept-of-composition/src/components/ExpenseDate.css b/code/10-the-concept-of-composition/src/components/ExpenseDate.css
new file mode 100644
index 0000000000..d69691de84
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/ExpenseDate.css
@@ -0,0 +1,26 @@
+.expense-date {
+ display: flex;
+ flex-direction: column;
+ width: 5.5rem;
+ height: 5.5rem;
+ border: 1px solid #ececec;
+ background-color: #2a2a2a;
+ color: white;
+ border-radius: 12px;
+ align-items: center;
+ justify-content: center;
+}
+
+.expense-date__month {
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.expense-date__year {
+ font-size: 0.75rem;
+}
+
+.expense-date__day {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
diff --git a/code/10-the-concept-of-composition/src/components/ExpenseDate.js b/code/10-the-concept-of-composition/src/components/ExpenseDate.js
new file mode 100644
index 0000000000..ba5698cf0d
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/ExpenseDate.js
@@ -0,0 +1,17 @@
+import './ExpenseDate.css';
+
+function ExpenseDate(props) {
+ const month = props.date.toLocaleString('en-US', { month: 'long' });
+ const day = props.date.toLocaleString('en-US', { day: '2-digit' });
+ const year = props.date.getFullYear();
+
+ return (
+
+
{month}
+
{year}
+
{day}
+
+ );
+}
+
+export default ExpenseDate;
diff --git a/code/10-the-concept-of-composition/src/components/ExpenseItem.css b/code/10-the-concept-of-composition/src/components/ExpenseItem.css
new file mode 100644
index 0000000000..aba2913253
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/ExpenseItem.css
@@ -0,0 +1,54 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.5rem;
+ margin: 1rem 0;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/10-the-concept-of-composition/src/components/ExpenseItem.js b/code/10-the-concept-of-composition/src/components/ExpenseItem.js
new file mode 100644
index 0000000000..cdc6cee206
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/ExpenseItem.js
@@ -0,0 +1,17 @@
+import ExpenseDate from './ExpenseDate';
+import Card from './Card';
+import './ExpenseItem.css';
+
+function ExpenseItem(props) {
+ return (
+
+
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/10-the-concept-of-composition/src/components/Expenses.css b/code/10-the-concept-of-composition/src/components/Expenses.css
new file mode 100644
index 0000000000..9b05ca92dc
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/Expenses.css
@@ -0,0 +1,7 @@
+.expenses {
+ padding: 1rem;
+ background-color: rgb(31, 31, 31);
+ margin: 2rem auto;
+ width: 50rem;
+ max-width: 95%;
+}
diff --git a/code/10-the-concept-of-composition/src/components/Expenses.js b/code/10-the-concept-of-composition/src/components/Expenses.js
new file mode 100644
index 0000000000..c42f88321d
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/components/Expenses.js
@@ -0,0 +1,32 @@
+import ExpenseItem from './ExpenseItem';
+import Card from './Card';
+import './Expenses.css';
+
+function Expenses(props) {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default Expenses;
diff --git a/code/10-the-concept-of-composition/src/index.css b/code/10-the-concept-of-composition/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/10-the-concept-of-composition/src/index.js b/code/10-the-concept-of-composition/src/index.js
new file mode 100644
index 0000000000..778ec1ba20
--- /dev/null
+++ b/code/10-the-concept-of-composition/src/index.js
@@ -0,0 +1,7 @@
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/code/11-finished/package.json b/code/11-finished/package.json
new file mode 100644
index 0000000000..b16a8faa39
--- /dev/null
+++ b/code/11-finished/package.json
@@ -0,0 +1,38 @@
+{
+ "name": "react-complete-guide",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.6",
+ "@testing-library/react": "^11.2.2",
+ "@testing-library/user-event": "^12.5.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "react-scripts": "4.0.1",
+ "web-vitals": "^0.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/code/11-finished/public/favicon.ico b/code/11-finished/public/favicon.ico
new file mode 100644
index 0000000000..a11777cc47
Binary files /dev/null and b/code/11-finished/public/favicon.ico differ
diff --git a/code/11-finished/public/index.html b/code/11-finished/public/index.html
new file mode 100644
index 0000000000..aa069f27cb
--- /dev/null
+++ b/code/11-finished/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
diff --git a/code/11-finished/public/logo192.png b/code/11-finished/public/logo192.png
new file mode 100644
index 0000000000..fc44b0a379
Binary files /dev/null and b/code/11-finished/public/logo192.png differ
diff --git a/code/11-finished/public/logo512.png b/code/11-finished/public/logo512.png
new file mode 100644
index 0000000000..a4e47a6545
Binary files /dev/null and b/code/11-finished/public/logo512.png differ
diff --git a/code/11-finished/public/manifest.json b/code/11-finished/public/manifest.json
new file mode 100644
index 0000000000..080d6c77ac
--- /dev/null
+++ b/code/11-finished/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/code/11-finished/public/robots.txt b/code/11-finished/public/robots.txt
new file mode 100644
index 0000000000..e9e57dc4d4
--- /dev/null
+++ b/code/11-finished/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/code/11-finished/src/App.js b/code/11-finished/src/App.js
new file mode 100644
index 0000000000..c7b17821a7
--- /dev/null
+++ b/code/11-finished/src/App.js
@@ -0,0 +1,43 @@
+import React from 'react';
+
+import Expenses from './components/Expenses/Expenses';
+
+const App = () => {
+ const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
+
+ // return React.createElement(
+ // 'div',
+ // {},
+ // React.createElement('h2', {}, "Let's get started!"),
+ // React.createElement(Expenses, { items: expenses })
+ // );
+
+ return (
+
+
Let's get started!
+
+
+ );
+}
+
+export default App;
diff --git a/code/11-finished/src/components/Expenses/ExpenseDate.css b/code/11-finished/src/components/Expenses/ExpenseDate.css
new file mode 100644
index 0000000000..d69691de84
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/ExpenseDate.css
@@ -0,0 +1,26 @@
+.expense-date {
+ display: flex;
+ flex-direction: column;
+ width: 5.5rem;
+ height: 5.5rem;
+ border: 1px solid #ececec;
+ background-color: #2a2a2a;
+ color: white;
+ border-radius: 12px;
+ align-items: center;
+ justify-content: center;
+}
+
+.expense-date__month {
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.expense-date__year {
+ font-size: 0.75rem;
+}
+
+.expense-date__day {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
diff --git a/code/11-finished/src/components/Expenses/ExpenseDate.js b/code/11-finished/src/components/Expenses/ExpenseDate.js
new file mode 100644
index 0000000000..0b307c24ad
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/ExpenseDate.js
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import './ExpenseDate.css';
+
+const ExpenseDate = (props) => {
+ const month = props.date.toLocaleString('en-US', { month: 'long' });
+ const day = props.date.toLocaleString('en-US', { day: '2-digit' });
+ const year = props.date.getFullYear();
+
+ return (
+
+
{month}
+
{year}
+
{day}
+
+ );
+};
+
+export default ExpenseDate;
diff --git a/code/11-finished/src/components/Expenses/ExpenseItem.css b/code/11-finished/src/components/Expenses/ExpenseItem.css
new file mode 100644
index 0000000000..aba2913253
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/ExpenseItem.css
@@ -0,0 +1,54 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.5rem;
+ margin: 1rem 0;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/code/11-finished/src/components/Expenses/ExpenseItem.js b/code/11-finished/src/components/Expenses/ExpenseItem.js
new file mode 100644
index 0000000000..b180c46841
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/ExpenseItem.js
@@ -0,0 +1,19 @@
+import React from 'react';
+
+import ExpenseDate from './ExpenseDate';
+import Card from '../UI/Card';
+import './ExpenseItem.css';
+
+const ExpenseItem = (props) => {
+ return (
+
+
+
+
{props.title}
+
${props.amount}
+
+
+ );
+}
+
+export default ExpenseItem;
diff --git a/code/11-finished/src/components/Expenses/Expenses.css b/code/11-finished/src/components/Expenses/Expenses.css
new file mode 100644
index 0000000000..9b05ca92dc
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/Expenses.css
@@ -0,0 +1,7 @@
+.expenses {
+ padding: 1rem;
+ background-color: rgb(31, 31, 31);
+ margin: 2rem auto;
+ width: 50rem;
+ max-width: 95%;
+}
diff --git a/code/11-finished/src/components/Expenses/Expenses.js b/code/11-finished/src/components/Expenses/Expenses.js
new file mode 100644
index 0000000000..7128bcf77a
--- /dev/null
+++ b/code/11-finished/src/components/Expenses/Expenses.js
@@ -0,0 +1,34 @@
+import React from 'react';
+
+import ExpenseItem from './ExpenseItem';
+import Card from '../UI/Card';
+import './Expenses.css';
+
+const Expenses = (props) => {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default Expenses;
diff --git a/code/11-finished/src/components/UI/Card.css b/code/11-finished/src/components/UI/Card.css
new file mode 100644
index 0000000000..166cffe458
--- /dev/null
+++ b/code/11-finished/src/components/UI/Card.css
@@ -0,0 +1,4 @@
+.card {
+ border-radius: 12px;
+ box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
+}
diff --git a/code/11-finished/src/components/UI/Card.js b/code/11-finished/src/components/UI/Card.js
new file mode 100644
index 0000000000..841fb93fa3
--- /dev/null
+++ b/code/11-finished/src/components/UI/Card.js
@@ -0,0 +1,11 @@
+import React from 'react';
+
+import './Card.css';
+
+const Card = (props) => {
+ const classes = 'card ' + props.className;
+
+ return {props.children}
;
+};
+
+export default Card;
diff --git a/code/11-finished/src/index.css b/code/11-finished/src/index.css
new file mode 100644
index 0000000000..72399cc5c6
--- /dev/null
+++ b/code/11-finished/src/index.css
@@ -0,0 +1,15 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap');
+
+* {
+ box-sizing: border-box;
+}
+
+html {
+ font-family: 'Noto Sans JP', sans-serif;
+}
+
+body {
+ margin: 0;
+ background-color: #3f3f3f;
+}
+
diff --git a/code/11-finished/src/index.js b/code/11-finished/src/index.js
new file mode 100644
index 0000000000..9065e05326
--- /dev/null
+++ b/code/11-finished/src/index.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+
+import './index.css';
+import App from './App';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/extra-files/ExpenseDate.css b/extra-files/ExpenseDate.css
new file mode 100644
index 0000000000..d69691de84
--- /dev/null
+++ b/extra-files/ExpenseDate.css
@@ -0,0 +1,26 @@
+.expense-date {
+ display: flex;
+ flex-direction: column;
+ width: 5.5rem;
+ height: 5.5rem;
+ border: 1px solid #ececec;
+ background-color: #2a2a2a;
+ color: white;
+ border-radius: 12px;
+ align-items: center;
+ justify-content: center;
+}
+
+.expense-date__month {
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.expense-date__year {
+ font-size: 0.75rem;
+}
+
+.expense-date__day {
+ font-size: 1.5rem;
+ font-weight: bold;
+}
diff --git a/extra-files/ExpenseItem.css b/extra-files/ExpenseItem.css
new file mode 100644
index 0000000000..22eabe9e80
--- /dev/null
+++ b/extra-files/ExpenseItem.css
@@ -0,0 +1,56 @@
+.expense-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
+ padding: 0.5rem;
+ margin: 1rem 0;
+ border-radius: 12px;
+ background-color: #4b4b4b;
+}
+
+.expense-item__description {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ align-items: flex-end;
+ flex-flow: column-reverse;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+.expense-item h2 {
+ color: #3a3a3a;
+ font-size: 1rem;
+ flex: 1;
+ margin: 0 1rem;
+ color: white;
+}
+
+.expense-item__price {
+ font-size: 1rem;
+ font-weight: bold;
+ color: white;
+ background-color: #40005d;
+ border: 1px solid white;
+ padding: 0.5rem;
+ border-radius: 12px;
+}
+
+@media (min-width: 580px) {
+ .expense-item__description {
+ flex-direction: row;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+ }
+
+ .expense-item__description h2 {
+ font-size: 1.25rem;
+ }
+
+ .expense-item__price {
+ font-size: 1.25rem;
+ padding: 0.5rem 1.5rem;
+ }
+}
\ No newline at end of file
diff --git a/extra-files/Expenses.css b/extra-files/Expenses.css
new file mode 100644
index 0000000000..2a3c9d0fbd
--- /dev/null
+++ b/extra-files/Expenses.css
@@ -0,0 +1,9 @@
+.expenses {
+ padding: 1rem;
+ background-color: rgb(31, 31, 31);
+ margin: 2rem auto;
+ width: 50rem;
+ max-width: 95%;
+ border-radius: 12px;
+ box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
+}
diff --git a/extra-files/expenses.txt b/extra-files/expenses.txt
new file mode 100644
index 0000000000..ec90c0623f
--- /dev/null
+++ b/extra-files/expenses.txt
@@ -0,0 +1,21 @@
+const expenses = [
+ {
+ id: 'e1',
+ title: 'Toilet Paper',
+ amount: 94.12,
+ date: new Date(2020, 7, 14),
+ },
+ { id: 'e2', title: 'New TV', amount: 799.49, date: new Date(2021, 2, 12) },
+ {
+ id: 'e3',
+ title: 'Car Insurance',
+ amount: 294.67,
+ date: new Date(2021, 2, 28),
+ },
+ {
+ id: 'e4',
+ title: 'New Desk (Wooden)',
+ amount: 450,
+ date: new Date(2021, 5, 12),
+ },
+ ];
\ No newline at end of file
diff --git a/slides/slides.pdf b/slides/slides.pdf
new file mode 100644
index 0000000000..01c2ca8ae3
Binary files /dev/null and b/slides/slides.pdf differ