├── 01 - Introduction
└── intro.txt
├── 02 - Modern JS Fundamentals
├── index.html
├── script.js
└── style.css
├── 03 - Fancy Counter
├── index.html
├── resources.txt
├── script.js
└── style.css
├── 04 - Word Analytics
├── index.html
├── resources.txt
├── script.js
└── style.css
├── 06 - CorpComment
├── Counter Component
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Feedback List Component #1
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Feedback List Component #2
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Final Loose Ends
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Form (Submit) Component
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Hashtag List Component
│ ├── index.html
│ ├── script.js
│ └── style.css
├── More Refactoring
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Project Setup
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Refactoring
│ ├── index.html
│ ├── script.js
│ └── style.css
├── Submit Component
│ ├── index.html
│ ├── script.js
│ └── style.css
├── VS Code Extension (Live-Server)
│ ├── index.html
│ ├── script.js
│ └── style.css
└── resources.txt
├── 08 - rmtDev
├── Active Job Item
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Router.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Async Await
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Bookmarks Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Bookmarks.js
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Router.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Build Process (webpack)
│ ├── babel.config.js
│ ├── dist
│ │ ├── index.html
│ │ ├── main.css
│ │ ├── main.js
│ │ └── main.js.LICENSE.txt
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ │ ├── common.js
│ │ ├── components
│ │ │ ├── Bookmarks.js
│ │ │ ├── Error.js
│ │ │ ├── JobDetails.js
│ │ │ ├── JobList.js
│ │ │ ├── Pagination.js
│ │ │ ├── Router.js
│ │ │ ├── Search.js
│ │ │ ├── Sorting.js
│ │ │ ├── Spinner.js
│ │ │ └── Storage.js
│ │ ├── index.css
│ │ ├── index.html
│ │ └── index.js
│ └── webpack.config.js
├── Error Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Improving Fetch Calls
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Job List Component
│ ├── index.css
│ ├── index.html
│ └── index.js
├── Modularity with ES Modules
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── More Refactoring
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Pagination Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Project Setup
│ ├── index.css
│ ├── index.html
│ └── index.js
├── Refactor Fetch Calls
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Refactoring
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ └── Spinner.js
├── Router Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Router.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Search Component
│ ├── index.css
│ ├── index.html
│ └── index.js
├── Sorting Component #2
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Sorting Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── State
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ └── Spinner.js
├── Storage Component
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Bookmarks.js
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Router.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ ├── Spinner.js
│ │ └── Storage.js
├── Taking Care of Details
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ └── src
│ │ ├── common.js
│ │ └── components
│ │ ├── Bookmarks.js
│ │ ├── Error.js
│ │ ├── JobDetails.js
│ │ ├── JobList.js
│ │ ├── Pagination.js
│ │ ├── Router.js
│ │ ├── Search.js
│ │ ├── Sorting.js
│ │ ├── Spinner.js
│ │ └── Storage.js
└── resources.txt
├── 09 - Supplemental
├── Formatting in JS
│ ├── babel.config.js
│ ├── dist
│ │ ├── index.html
│ │ ├── main.css
│ │ ├── main.js
│ │ └── main.js.LICENSE.txt
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ │ ├── common.js
│ │ ├── components
│ │ │ ├── Bookmarks.js
│ │ │ ├── Error.js
│ │ │ ├── JobDetails.js
│ │ │ ├── JobList.js
│ │ │ ├── Pagination.js
│ │ │ ├── Router.js
│ │ │ ├── Search.js
│ │ │ ├── Sorting.js
│ │ │ ├── Spinner.js
│ │ │ └── Storage.js
│ │ ├── index.css
│ │ ├── index.html
│ │ └── index.js
│ └── webpack.config.js
└── Has the For Loop Been Replaced by forEach
│ ├── index.html
│ ├── script.js
│ └── style.css
├── bugs.md
├── readme.md
└── slides.md
/01 - Introduction/intro.txt:
--------------------------------------------------------------------------------
1 | Welcome to the course!
2 |
3 | We will build some beautiful projects in this course. Sometimes, you will have to copy-paste an image URL or something else. You can find all those resources in a 'resources.txt' file in the folder for the project.
4 |
5 | Glad to have you on board, let's get started!
6 |
7 | Wesley
--------------------------------------------------------------------------------
/02 - Modern JS Fundamentals/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
13 |
15 |
16 |
17 |
18 |
19 | Overview of Modern JS Fundamentals
20 |
21 |
22 |
23 | This is a quick overview of modern JS
24 |
25 |
26 |
--------------------------------------------------------------------------------
/02 - Modern JS Fundamentals/script.js:
--------------------------------------------------------------------------------
1 | // -- variables (var/let/const) & data types/structures (strings/numbers/booleans/arrays/objects) --
2 | // const description = 'We need a new floor.';
3 | // const squareMeters = 100;
4 | // const specialCoating = true;
5 | // const floorOptions = ['carpet', 'hardwood', 'tiles'];
6 | // const renovationJob = {
7 | // ownerName: 'John',
8 | // maximumPrice: 5000,
9 | // category: 'bathroom',
10 | // newShower: true
11 | // };
12 |
13 |
14 | // -- traditional functions vs arrow functions --
15 |
16 | // function calculatePrice(sqMeters) {
17 | // return 1000 + sqMeters;
18 | // }
19 |
20 | // var calculatePrice = function(sqMeters) {
21 | // return 1000 + sqMeters;
22 | // };
23 |
24 | // const calculatePrice = (sqMeters) => {
25 | // return 1000 + sqMeters;
26 | // };
27 |
28 | // const calculatePrice = sqMeters => 1000 + sqMeters;
29 |
30 |
31 | // -- string concatenation vs template literals --
32 | // const price = 5000;
33 | // const result = 'The total cost will be: ' + price;
34 | // const result = `The total cost will be: ${price}`;
35 |
36 |
37 | // -- if-else vs ternary operator --
38 | // const price = 5000;
39 |
40 | // if (price) {
41 | // console.log('hello');
42 | // } else {
43 | // console.log('blabla');
44 | // }
45 |
46 | // price > 3000 ? console.log('expensive') : console.log('cheap');
47 |
48 |
49 | // -- manipulating HTML and CSS --
50 | // const headingEl = document.querySelector('.heading');
51 |
52 | // headingEl.textContent = 'Hello everyone!';
53 | // headingEl.innerHTML = 'Hello everyone!';
54 | // headingEl.insertAdjacentHTML('beforebegin', 'Hello everyone!');
55 |
56 | // headingEl.style.fontSize = '55px';
57 | // headingEl.classList.add('heading--big');
58 |
59 |
60 | // -- events and functions for handling events (also called "event handlers") --
61 | // const headingEl = document.querySelector('.heading');
62 |
63 | // const clickHandler = () => {
64 | // headingEl.style.color = 'red';
65 | // console.log('changed color');
66 | // };
67 |
68 | // headingEl.addEventListener('click', clickHandler);
--------------------------------------------------------------------------------
/02 - Modern JS Fundamentals/style.css:
--------------------------------------------------------------------------------
1 | .heading {
2 | font-size: 15px;
3 | }
4 |
5 | .heading--big {
6 | font-size: 55px;
7 | }
--------------------------------------------------------------------------------
/03 - Fancy Counter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Fancy Counter
17 |
18 |
19 |
20 |
21 |
Fancy Counter
22 |
23 |
0
24 |
25 |
28 |
29 |
30 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/03 - Fancy Counter/resources.txt:
--------------------------------------------------------------------------------
1 | ####### Font Link
2 |
3 |
4 |
5 |
6 |
7 |
8 | ####### Font Awesome
9 |
10 |
11 |
--------------------------------------------------------------------------------
/03 - Fancy Counter/script.js:
--------------------------------------------------------------------------------
1 | const counterEl = document.querySelector('.counter');
2 | const increaseButtonEl = document.querySelector('.counter__button--increase');
3 | const decreaseButtonEl = document.querySelector('.counter__button--decrease');
4 | const resetButtonEl = document.querySelector('.counter__reset-button');
5 | const counterValueEl = document.querySelector('.counter__value');
6 | const counterTitleEl = document.querySelector('.counter__title');
7 |
8 | resetButtonEl.addEventListener('click', () => {
9 | // set counter value to 0
10 | counterValueEl.textContent = 0;
11 |
12 | // reset background color
13 | counterEl.classList.remove('counter--limit');
14 |
15 | // reset counter title
16 | counterTitleEl.textContent = 'Fancy Counter';
17 |
18 | // enable increase and decrease buttons
19 | increaseButtonEl.disabled = false;
20 | decreaseButtonEl.disabled = false;
21 |
22 | // unfocus (blur) reset button
23 | resetButtonEl.blur();
24 | });
25 |
26 | decreaseButtonEl.addEventListener('click', () => {
27 | // get current value of counter
28 | const currentValue = counterValueEl.textContent;
29 |
30 | // convert value value to number type
31 | const currentValueAsNumber = +currentValue;
32 |
33 | // decrement by 1
34 | let newValue = currentValueAsNumber - 1;
35 |
36 | // check if new value is less than 0
37 | if (newValue < 0) {
38 | // if it is, force it to be 0 instead
39 | newValue = 0;
40 | }
41 |
42 | // update counter value with new value
43 | counterValueEl.textContent = newValue;
44 |
45 | // unfocus (blur) button
46 | decreaseButtonEl.blur();
47 | });
48 |
49 | const incrementCounter = () => {
50 | // get current value of counter
51 | const currentValue = counterValueEl.textContent;
52 |
53 | // convert value to number type
54 | const currentValueAsNumber = +currentValue;
55 |
56 | // increment by 1
57 | let newValue = currentValueAsNumber + 1;
58 |
59 | // check if new value is greater than 5
60 | if (newValue > 5) {
61 | // if it is, force it to be 5 instead
62 | newValue = 5;
63 |
64 | // give visual indicator that limit has been reached
65 | counterEl.classList.add('counter--limit');
66 |
67 | // update counter title to say limit has been reached
68 | counterTitleEl.innerHTML = 'Limit! Buy Pro for >5';
69 |
70 | // disable increase and decrease buttons
71 | increaseButtonEl.disabled = true;
72 | decreaseButtonEl.disabled = true;
73 | }
74 |
75 | // set counter element with new value
76 | counterValueEl.textContent = newValue;
77 |
78 | // unfocus (blur) button
79 | increaseButtonEl.blur();
80 | }
81 |
82 | increaseButtonEl.addEventListener('click', incrementCounter);
83 | document.addEventListener('keydown', incrementCounter);
--------------------------------------------------------------------------------
/03 - Fancy Counter/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | button {
8 | all: unset;
9 | }
10 |
11 | body {
12 | font-family: 'Inter', sans-serif;
13 | height: 100vh;
14 | background-image: radial-gradient(ellipse, #385300, #212900);
15 | display: flex;
16 | justify-content: center;
17 | align-items: center;
18 | }
19 |
20 | .counter {
21 | background-color: #bef227;
22 | width: 476px;
23 | height: 615px;
24 | border-radius: 12px;
25 | box-shadow: 0 25px 121px rgba(0, 0, 0, 0.5);
26 | display: flex;
27 | flex-direction: column;
28 | align-items: center;
29 | transition: all 0.4s;
30 | }
31 |
32 | .counter--limit {
33 | background-color: #a3d11b;
34 | }
35 |
36 | .counter__title {
37 | opacity: 0.6;
38 | text-transform: uppercase;
39 | letter-spacing: 1px;
40 | width: 200px;
41 | text-align: center;
42 | line-height: 0.9;
43 | font-weight: 500;
44 | font-size: 32px;
45 | margin-top: 60px;
46 | }
47 |
48 | .counter__value {
49 | color: #1d2507;
50 | font-size: 200px;
51 | font-weight: 600;
52 | margin-top: 10px;
53 | }
54 |
55 | .counter__reset-button {
56 | cursor: pointer;
57 | }
58 |
59 | .counter__reset-icon {
60 | opacity: 0.3;
61 | font-size: 35px;
62 | transition: all 0.4s;
63 | }
64 |
65 | .counter__reset-icon:hover {
66 | opacity: 0.5;
67 | }
68 |
69 | .counter__buttons {
70 | background-color: #1d2507;
71 | height: 116px;
72 | width: 100%;
73 | margin-top: auto;
74 | border-bottom-right-radius: 10px;
75 | border-bottom-left-radius: 10px;
76 | display: flex;
77 | }
78 |
79 | .counter__button {
80 | flex: 1;
81 | display: flex;
82 | justify-content: center;
83 | align-items: center;
84 | cursor: pointer;
85 | transition: all 0.4s;
86 | }
87 |
88 | .counter__button:hover {
89 | background-color: #212b06;
90 | }
91 |
92 | .counter__button--decrease {
93 |
94 | }
95 |
96 | .counter__button--increase {
97 | border-left: 1px solid rgba(189, 254, 0, 0.15);
98 | }
99 |
100 | .counter__icon {
101 | color: #bdfe00;
102 | opacity: 0.9;
103 | font-size: 40px;
104 | }
105 |
106 | .counter__icon--minus {
107 |
108 | }
109 |
110 | .counter__icon--plus {
111 |
112 | }
113 |
114 | @media (max-width: 680px) or (max-height: 730px) {
115 | .counter {
116 | width: 100%;
117 | height: 100%;
118 | border-radius: 0;
119 | }
120 |
121 | .counter__title {
122 | margin-top: 100px;
123 | }
124 |
125 | .counter__buttons {
126 | border-bottom-left-radius: 0;
127 | border-bottom-right-radius: 0;
128 | }
129 | }
--------------------------------------------------------------------------------
/04 - Word Analytics/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Word Analytics
16 |
17 |
18 |
19 |
20 |
21 |
22 | WordAnalytics
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 | 0
35 | Characters
36 |
37 |
41 |
42 | 2200
43 | Facebook
44 |
45 |
46 |
47 |
48 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/04 - Word Analytics/resources.txt:
--------------------------------------------------------------------------------
1 | ####### Image URL
2 |
3 | https://bytegrad.com/course-assets/images/rn-image-1.png
4 |
5 |
6 | ####### Font Link
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/04 - Word Analytics/script.js:
--------------------------------------------------------------------------------
1 | const textareaEl = document.querySelector('.textarea');
2 | const charactersNumberEl = document.querySelector('.stat__number--characters');
3 | const twitterNumberEl = document.querySelector('.stat__number--twitter');
4 | const facebookNumberEl = document.querySelector('.stat__number--facebook');
5 | const wordsNumberEl = document.querySelector('.stat__number--words');
6 |
7 | const inputHandler = () => {
8 | // example of input validation
9 | if (textareaEl.value.includes('