├── 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 |
30 | 0 31 |

Words

32 |
33 |
34 | 0 35 |

Characters

36 |
37 |
38 | 39 |

Twitter

40 |
41 |
42 | 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('