├── .vscode └── settings.json ├── 00-assets ├── contribution-demo.md ├── contribution-desc.md ├── main.js ├── projectList.json └── style.css ├── 01-randomColor ├── app.js ├── index.html └── main.css ├── 02-todo ├── app.js ├── index.html └── main.css ├── 03-budgety ├── ReadMe.md ├── app.js ├── index.html └── style.css ├── 04-drumKit ├── app.js ├── drum.html ├── icons │ ├── icon-192-192.png │ └── icon-512-512.png ├── index.html ├── manifest.json ├── service-worker.js ├── sounds │ ├── boom.wav │ ├── clap.wav │ ├── hihat.wav │ ├── kick.wav │ ├── openhat.wav │ ├── ride.wav │ ├── snare.wav │ ├── tink.wav │ └── tom.wav └── style.css ├── 05-formValidator ├── app.js ├── index.html └── style.css ├── 06-rocketGame ├── app.js ├── index.html └── style.css ├── 07-clock ├── app.js ├── index.html ├── style.css └── wesbos.html ├── 08-movieSeat ├── index.html ├── script.js └── style.css ├── 09-boxShadow ├── app.js ├── index.html └── style.css ├── 10-flexGallery ├── app.js ├── index.html └── style.css ├── 11-typeAhead ├── app.js ├── index.html └── style.css ├── 12-drawing ├── app.js └── index.html ├── 13-checkboxes ├── app.js ├── index.html └── style.css ├── 14-slider ├── app.js ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── person-1.jpeg ├── index.html └── style.css ├── 16-KONAMI ├── app.js └── index.html ├── 17-stickyNav ├── app.js ├── index.html └── style.css ├── 18-scrollToSlide ├── app.js ├── index.html └── style.css ├── 19-parallaxScroll ├── app.js ├── index.html ├── mountain.jpg └── style.css ├── 20-localStorage ├── app.js ├── index.html ├── oh-la-la.jpeg └── style.css ├── 21-mouseMove ├── app.js └── index.html ├── 22-notable ├── app.js ├── index.html └── style.css ├── 23-sortList ├── app.js ├── index.html ├── sortArticle.html └── style.css ├── 24-jsonFetch ├── assets │ ├── app.js │ └── projects.json └── index.html ├── 25-pomodoro ├── app.js ├── index.html └── style.css ├── 26-followLinks ├── app.js ├── index.html └── style.css ├── 27-dragDrop ├── app.js ├── index.html └── style.css ├── 28-bmiCalc ├── app.js ├── index.html └── style.css ├── 29-currencyConvert ├── app.js ├── index.html └── style.css ├── 30-articlePrev ├── app.js ├── img │ ├── avatar.jpg │ ├── drawers.jpg │ ├── fb.svg │ ├── pt.svg │ ├── share.svg │ └── tw.svg ├── index.html └── style.css ├── 31-faqAccordion ├── app.js ├── hero.svg ├── index.html └── style.css ├── 32-threader ├── app.js ├── index.html └── style.css ├── 33-contactList ├── app.js ├── index.html └── style.css ├── 34-darkMode ├── fixGradTrans.html ├── index.html └── style.css ├── 35-fluffyFrn ├── app.js ├── index.html └── style.css ├── 36-lineChart ├── app.js ├── index.html └── style.css ├── 37-budgetApp ├── app.js ├── index.html └── style.css ├── 38-duoToneCard ├── app.js ├── index.html └── style.css ├── 39-contactApp ├── app.js ├── index.html ├── main.js ├── readme.md └── style.css ├── 40-weatherClock ├── api.js ├── app.js ├── index.html ├── readme.md └── style.css ├── 41-lazyLoading ├── app.js ├── index.html ├── placeholder.jpeg ├── readme.md └── style.css ├── 42-JSBank ├── app.js ├── index.html ├── readme.md └── style.css ├── 43-Furnit ├── app.js ├── index.html ├── products.js ├── readme.md └── style.css ├── 44-pagination ├── app.js ├── index.html ├── readme.md └── style.css ├── Console ├── 03 FizzBuzz.html ├── arrayCardio-01.html ├── arrayCardio-02.html ├── codewars.html ├── devTool.html ├── reduce.html └── referenceVsCopy.html ├── README.md └── index.html /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "prettier.singleQuote": true, 4 | "prettier.tabWidth": 4 5 | } -------------------------------------------------------------------------------- /00-assets/contribution-demo.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/00-assets/contribution-demo.md -------------------------------------------------------------------------------- /00-assets/contribution-desc.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/00-assets/contribution-desc.md -------------------------------------------------------------------------------- /00-assets/main.js: -------------------------------------------------------------------------------- 1 | const tableBody = document.querySelector('.tbody'); 2 | const serial = document.querySelector('[data-col]'); 3 | let items = []; 4 | 5 | fetch('00-assets/projectList.json') 6 | .then((response) => response.json()) 7 | .then((data) => { 8 | items.push(...data); 9 | populateUI(tableBody, items); 10 | }); 11 | 12 | function populateUI(list, arr = []) { 13 | list.innerHTML = arr.map((el) => { 14 | return ` 15 | ${ 16 | el.index < 10 ? '0' + el.index: el.index 17 | } 18 | 19 | 21 | 22 | ${el.name} 23 | 24 | 25 | 26 | 27 | 29 | 30 | ${el.codeBase} 31 | 32 | 33 | 34 | ${el.notes} 35 | 36 | `; 37 | }) 38 | .join(''); 39 | } 40 | 41 | function sortSerial() { 42 | const col = this.dataset.col; 43 | const order = this.dataset.order; 44 | 45 | if (order == 'desc') { 46 | this.dataset.order = 'asc'; 47 | items = items.sort((a, b) => (a[col] > b[col] ? 1: -1)); 48 | } else { 49 | this.dataset.order = 'desc'; 50 | items = items.sort((a, b) => (a[col] < b[col] ? 1: -1)); 51 | } 52 | 53 | populateUI(tableBody, items); 54 | } 55 | 56 | serial.addEventListener('click', sortSerial); -------------------------------------------------------------------------------- /00-assets/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Sniglet&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | html { 9 | font-size: 10px; 10 | font-family: sans-serif; 11 | } 12 | body { 13 | font-size: 1.5rem; 14 | line-height: 1.6; 15 | min-height: 100vh; 16 | background: radial-gradient(circle at center center, hsla(166,0%,10%,1) 0%,hsla(181,0%,10%,1) 29%,transparent 65%),linear-gradient(90deg, rgb(35,35,35) 0%, rgb(35,35,35) 50%,rgb(35,35,35) 50%, rgb(35,35,35) 100%); 17 | background-size: 7px 7px; 18 | } 19 | header { 20 | width: 98%; 21 | max-width: 80rem; 22 | min-height: 15rem; 23 | padding: 1rem; 24 | margin: 1rem auto; 25 | margin-bottom: 5rem; 26 | text-align: center; 27 | font-size: 1.75rem; 28 | border-radius: 1.25rem; 29 | background: repeating-linear-gradient(297deg, hsla(359,0%,70%,0.12) 0px,transparent 2px,hsla(359,0%,70%,0.12) 7px,transparent 9px,hsla(359,0%,70%,0.12) 14px,transparent 16px,hsla(359,0%,70%,0.12) 21px),repeating-linear-gradient(59deg, hsla(359,0%,70%,0.12) 0px,transparent 2px,hsla(359,0%,70%,0.12) 7px,transparent 9px,hsla(359,0%,70%,0.12) 14px,transparent 16px,hsla(359,0%,70%,0.12) 21px),repeating-linear-gradient(0deg, hsla(359,0%,70%,0.12) 0px,transparent 2px,hsla(359,0%,70%,0.12) 7px,transparent 9px,hsla(359,0%,70%,0.12) 14px,transparent 16px,hsla(359,0%,70%,0.12) 21px),linear-gradient(90deg, rgb(253,253,253),rgb(253,253,253)); 30 | } 31 | header > * { 32 | margin: 0.75rem 0; 33 | } 34 | header h1 { 35 | display: inline-block; 36 | line-height: 1.2; 37 | border-bottom: 1px solid #333; 38 | margin-bottom: 2rem; 39 | padding: 1rem 1rem 0 1rem; 40 | font-family: 'Sniglet', cursive; 41 | } 42 | header h1 span { 43 | background: #333; 44 | color: #ff0; 45 | padding: 1rem; 46 | padding-bottom: 0; 47 | } 48 | header a { 49 | text-decoration: none; 50 | margin: 0 0.5rem; 51 | color: #dc143c; 52 | } 53 | table.blueTable { 54 | background-color: #69d0b3; 55 | width: 98%; 56 | max-width: 60rem; 57 | min-height: 20rem; 58 | text-align: left; 59 | border-collapse: collapse; 60 | margin: 3rem auto; 61 | } 62 | table.blueTable td, 63 | table.blueTable th { 64 | padding: 1.25rem 0.5rem; 65 | } 66 | table.blueTable tbody tr td:first-child { 67 | text-align: center; 68 | font-family: Georgia, 'Times New Roman', Times, serif; 69 | } 70 | table.blueTable tbody td { 71 | font-size: 1.4rem; 72 | } 73 | table.blueTable tr:nth-child(even) { 74 | background: #b2fcff; 75 | } 76 | table.blueTable thead { 77 | background: #e43f5a; 78 | } 79 | table.blueTable thead th { 80 | font-size: 1.5rem; 81 | font-weight: 700; 82 | color: #fff; 83 | text-align: center; 84 | background: linear-gradient(145deg, #f44360, #cd3951); 85 | box-shadow: inset 12px 12px 24px #c2364d, 86 | inset -12px -12px 24px #ff4868; 87 | } 88 | table a { 89 | text-decoration: none; 90 | color: #333; 91 | margin-left: 0.5rem; 92 | padding-bottom: 0.25rem; 93 | border-bottom: 2px dotted #9f9f9f; 94 | transition: all 0.2s ease; 95 | font-weight: 700; 96 | } 97 | table a:hover { 98 | color: #000; 99 | } 100 | 101 | th:first-child { 102 | cursor: pointer; 103 | } -------------------------------------------------------------------------------- /01-randomColor/app.js: -------------------------------------------------------------------------------- 1 | let qs = selector => document.querySelector(selector); 2 | 3 | 4 | function getRGB() { 5 | // Random number from 0 to 255 6 | let red = Math.floor(Math.random() * 256); 7 | let green = Math.floor(Math.random() * 256); 8 | let blue = Math.floor(Math.random() * 256); 9 | 10 | let rgb = red + ', ' + green + ', ' + blue; 11 | 12 | return rgb; 13 | }; 14 | 15 | qs('.rgb-btn').addEventListener('click', () => { 16 | const rgbColor = `rgb(${getRGB()})`; 17 | //console.log(rgbColor); 18 | 19 | qs('.rgb').style.backgroundColor = rgbColor; 20 | 21 | // set the value in color name 22 | qs('.rgb-name').textContent = rgbColor; 23 | }); 24 | 25 | ///////////////////////////////// HEX 26 | 27 | let hexShort = () => Math.random().toString(16).substr(-6); 28 | //console.log(`hexa: ${hexa()}`); 29 | 30 | // .toString(16) gives us 15 hex values in Math.random()'s decimal. .substr(-6) returns the characters from the last 0 to 6. 31 | // Math.random() = 0.843879329 32 | // Math.random().toString(16) = 0.k3i5o67kjda8 33 | // Math.random().toString(16).substr(-6) = 7kjda8 34 | 35 | qs('.hex-btn').addEventListener('click', () => { 36 | let hexColor = `#${hexShort()}`; 37 | //console.log(hexColor); 38 | 39 | qs('.hex').style.backgroundColor = hexColor; 40 | 41 | // set the value in color name 42 | qs('.hex-name').textContent = hexColor; 43 | }); 44 | 45 | ///////// More Readable way 46 | 47 | let characters = 'ABCDEF0123456789'; 48 | 49 | function getHEX () { 50 | let result = ''; 51 | let charLength = characters.length; // 16 52 | 53 | let p = Math.floor(Math.random() * charLength); 54 | //console.log(p); 55 | 56 | for (let i = 0; i < 6; i++){ 57 | result += characters.charAt(Math.floor(Math.random() * charLength)); 58 | //console.log(result); 59 | //charAt is taking a string by the index and the loop is producing the strings from the character and result is storing them all one-by-one. 60 | }; 61 | 62 | return result; 63 | }; 64 | -------------------------------------------------------------------------------- /01-randomColor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Random Color Generator 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Random RGB Color Generator

17 |

RGB Code

18 | 19 |
20 |
21 | 22 |
23 |
24 |

Random Hexadecimal Color Generator

25 |

Hex Code

26 | 27 |
28 |
29 | 30 |

31 | Made with ❤️ by Tutul 32 |

33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /01-randomColor/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | body { 7 | width: 100%; 8 | font-family: sans-serif; 9 | background: #ededed; 10 | transition: all 0.1s linear; 11 | } 12 | 13 | section { 14 | width: 100%; 15 | height: 100vh; 16 | display: grid; 17 | place-items: center; 18 | } 19 | section div{ 20 | width: 90%; 21 | max-width: 500px; 22 | padding: 1rem; 23 | text-align: center; 24 | border-radius: 1rem; 25 | background: linear-gradient(145deg, #ffffff, #e6e6e6); 26 | box-shadow: inset 20px 20px 60px #d9d9d9, 27 | inset -20px -20px 60px #ffffff; 28 | } 29 | section div > * { 30 | margin: 0.75rem 0; 31 | } 32 | h2 { 33 | background: -webkit-linear-gradient(-110deg,#21dc53, #226721); 34 | -webkit-background-clip: text; 35 | -webkit-text-fill-color: transparent; 36 | } 37 | button { 38 | cursor: pointer; 39 | background: #fff; 40 | color: #EC5E0C; 41 | padding: 0.5rem 1rem; 42 | font-size: 1rem; 43 | transform: skew(-15deg); 44 | border: 2px solid #EC5E0C; 45 | } 46 | 47 | 48 | .signature { 49 | text-align: center; 50 | font-size: 0.85rem; 51 | width: 100%; 52 | position: fixed; 53 | bottom: 0.25rem; 54 | left: 0; 55 | } 56 | .signature a { 57 | text-decoration: none; 58 | color: initial; 59 | font-weight: bold; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /02-todo/app.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/02-todo/app.js -------------------------------------------------------------------------------- /02-todo/main.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/02-todo/main.css -------------------------------------------------------------------------------- /03-budgety/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Budgety App 2 | 3 | * This project is by [Jonas Schmedtmann](https://twitter.com/jonasschmedtman) in his [udemy course](https://www.udemy.com/course/the-complete-javascript-course). Re-made by me. 4 | 5 | * [Live](https://codepen.io/TutulDevs/full/eYZmYZj) 6 | 7 | * The top gradient is from [gradienta](https://gradienta.io/) -------------------------------------------------------------------------------- /04-drumKit/app.js: -------------------------------------------------------------------------------- 1 | let qs = selector => document.querySelector(selector); 2 | const keys = Array.from(document.querySelectorAll('.key')); 3 | 4 | const playSound = e => { 5 | const audio = qs(`audio[data-key="${e.keyCode}"]`); 6 | 7 | if (!audio) return; // IF !audio return nothing // not working tho 8 | 9 | audio.play(); 10 | audio.currentTime = 0; 11 | 12 | const key = qs(`.key[data-key="${e.keyCode}"]`); 13 | key.classList.add('playing'); 14 | }; 15 | 16 | // This is more accurate 17 | keys.forEach(el => el.addEventListener('click', () => { 18 | const kc = el.dataset.key; 19 | 20 | const audio = qs(`audio[data-key="${kc}"]`); 21 | audio.play(); 22 | audio.currentTime = 0; 23 | 24 | const key = qs(`.key[data-key="${kc}"]`); 25 | key.classList.add('playing'); 26 | })); 27 | 28 | let removeTransition = e => { 29 | if(e.propertyName !== 'transform') return; 30 | e.target.classList.remove('playing'); 31 | } 32 | 33 | window.addEventListener('keydown', playSound); 34 | keys.forEach(el => el.addEventListener('transitionend', removeTransition)); 35 | 36 | /////////////// Volume Controller 37 | 38 | qs('.vol-range').addEventListener('input', (e) => { 39 | 40 | let value = Number(e.target.value); 41 | const audio = Array.from(document.querySelectorAll('audio')); 42 | 43 | audio.forEach(el => { 44 | if (value == 1) { 45 | el.volume = 0.1; 46 | }else if (value == 2) { 47 | el.volume = 0.2; 48 | }else if (value == 3) { 49 | el.volume = 0.3; 50 | }else if (value == 4) { 51 | el.volume = 0.4; 52 | }else if (value == 5) { 53 | el.volume = 0.5; 54 | }else if (value == 6) { 55 | el.volume = 0.6; 56 | }else if (value == 7) { 57 | el.volume = 0.7; 58 | }else if (value == 8) { 59 | el.volume = 0.8; 60 | }else if (value == 9) { 61 | el.volume = 0.9; 62 | }else if (value == 10) { 63 | el.volume = 1.0; 64 | }; 65 | }); 66 | 67 | }); 68 | 69 | 70 | 71 | /* 72 | // Less accurate click event 73 | const clickToPlay = (e) => { 74 | const kc = e.path[1].dataset.key; 75 | console.log(e.path[1]); 76 | 77 | const audio = qs(`audio[data-key="${kc}"]`); 78 | audio.play(); 79 | audio.currentTime = 0; 80 | 81 | const key = qs(`.key[data-key="${kc}"]`); 82 | key.classList.add('playing'); 83 | } 84 | keys.forEach(el => el.addEventListener('click', clickToPlay)); 85 | */ 86 | -------------------------------------------------------------------------------- /04-drumKit/drum.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Drum Kit 7 | 8 | 9 | 10 |

This design is by Laasri Nadia. I might use this for later use.

11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /04-drumKit/icons/icon-192-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/icons/icon-192-192.png -------------------------------------------------------------------------------- /04-drumKit/icons/icon-512-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/icons/icon-512-512.png -------------------------------------------------------------------------------- /04-drumKit/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tutul's drumKit", 3 | "short_name": "drumKit", 4 | "theme_color": "#2196f3", 5 | "background_color": "#2196f3", 6 | "display": "standalone", 7 | "orientation": "portrait", 8 | "scope": "/", 9 | "start_url": "/", 10 | "lang": "en", 11 | "icons": [ 12 | { 13 | "src": "./icons/icon-512-512.png", 14 | "type": "image/png", 15 | "sizes": "512x512" 16 | }, 17 | { 18 | "src": "./icons/icon-192-192.png", 19 | "type": "image/png", 20 | "sizes": "192x192" 21 | }, 22 | { 23 | "src": "./icons/icon-192-192.png", 24 | "type": "image/png", 25 | "sizes": "512x512", 26 | "purpose": "any maskable" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /04-drumKit/service-worker.js: -------------------------------------------------------------------------------- 1 | const FILES_TO_CACHE = [ 2 | '/', 3 | './index.html', 4 | './style.css', 5 | './app.js', 6 | './sounds/boom.wav', 7 | './sounds/clap.wav', 8 | './sounds/hihat.wav', 9 | './sounds/kick.wav', 10 | './sounds/openhat.wav', 11 | './sounds/ride.wav', 12 | './sounds/snare.wav', 13 | './sounds/tink.wav', 14 | './sounds/tom.wav', 15 | ]; 16 | //UPDATE VERSION WHEN U UPDATE CODE 17 | const CACHE_NAME = 'STATIC_CACHE_V2'; 18 | 19 | self.addEventListener('install', (event) => { 20 | event.waitUntil( 21 | caches.open(CACHE_NAME).then((cache) => { 22 | cache.addAll(FILES_TO_CACHE); 23 | }) 24 | ); 25 | }); 26 | 27 | self.addEventListener('activate', (event) => { 28 | event.waitUntil( 29 | caches.keys().then((keyList) => { 30 | return Promise.all( 31 | keyList.map((key) => { 32 | if (key !== CACHE_NAME) { 33 | caches.delete(key); 34 | } 35 | }) 36 | ); 37 | }) 38 | ); 39 | }); 40 | 41 | self.addEventListener('fetch', (event) => { 42 | event.respondWith( 43 | caches 44 | .match(event.request) 45 | .then((response) => (response ? response : fetch(event.request))) 46 | ); 47 | }); 48 | -------------------------------------------------------------------------------- /04-drumKit/sounds/boom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/boom.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/clap.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/clap.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/hihat.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/kick.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/openhat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/openhat.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/ride.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/ride.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/snare.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/tink.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/tink.wav -------------------------------------------------------------------------------- /04-drumKit/sounds/tom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/04-drumKit/sounds/tom.wav -------------------------------------------------------------------------------- /05-formValidator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Form Validator 9 | 10 | 11 |
12 |
13 |

Register With Us

14 |
15 | 16 | 22 | Error message 23 |
24 |
25 | 26 | 32 | Error message 33 |
34 |
35 | 36 | 42 | Error message 43 |
44 |
45 | 46 | 52 | Error message 53 |
54 | 55 |
56 |
57 | 58 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /06-rocketGame/app.js: -------------------------------------------------------------------------------- 1 | const game = document.getElementById('game'); 2 | const rocket = document.getElementById('rocket'); 3 | const car = document.getElementById('car'); 4 | const showAlert = document.querySelector('h2'); 5 | 6 | function jump() { 7 | if (rocket.classList != 'animate') { 8 | rocket.classList.add('animate'); 9 | } 10 | 11 | setTimeout(function () { 12 | rocket.classList.remove('animate'); 13 | }, 750); 14 | 15 | const checkDead = setInterval(function () { 16 | const rocketBottom = rocket.computedStyleMap().get('bottom').value; 17 | const carRight = car.computedStyleMap().get('right').value; 18 | 19 | if (carRight > 85 && carRight < 90 && rocketBottom < 40) { 20 | showAlert.style.color = '#d84315'; 21 | showAlert.textContent = '😐 Tap to play again...'; 22 | car.style.animation = 'none'; 23 | } 24 | }, 25); 25 | } 26 | 27 | // Initializer 28 | game.addEventListener('click', () => { 29 | window.addEventListener('click', jump); 30 | 31 | window.addEventListener('keypress', (e) => 32 | e.keyCode === 32 ? jump() : '' 33 | ); 34 | 35 | showAlert.style.color = '#4CAF50'; 36 | showAlert.textContent = 'Playing...'; 37 | car.style.display = 'block'; 38 | car.style.animation = 'car 4s linear infinite'; 39 | }); 40 | 41 | /* 42 | 1. get the dom 43 | 2. call the event 44 | 3. add the animation if it doesn't have already 45 | 4.remove the animation if it has the class after the animation time (750ms) 46 | 47 | 5. Check every 10 ms if the two element are on top of each other 48 | 6. get bottom position of 🚀 and right position of 🚕 49 | 50 | 7. put the event in another listener to initiate them 51 | 52 | */ 53 | -------------------------------------------------------------------------------- /06-rocketGame/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 🚀 Rocket Game 7 | 8 | 9 | 10 |
11 |
12 |

Tap to play

13 |
🚀
14 |
🚕
15 |
16 |
17 | 18 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /06-rocketGame/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 10px; 9 | line-height: 1; 10 | font-family: sans-serif; 11 | } 12 | 13 | main { 14 | width: 100%; 15 | height: 100vh; 16 | display: grid; 17 | place-items: center; 18 | background: #99bcd1; 19 | } 20 | 21 | h2 { 22 | padding: 2rem; 23 | text-align: center; 24 | color: #00695c; 25 | transition: all 0.3s linear; 26 | font-size: 2.5rem; 27 | } 28 | 29 | #game { 30 | width: 95%; 31 | margin: 0 auto; 32 | max-width: 80rem; 33 | height: 20rem; 34 | position: relative; 35 | overflow: hidden; 36 | 37 | border-radius: 5px; 38 | background: #bbcdd8; 39 | box-shadow: inset 5px 5px 10px #a6b6c0, inset -5px -5px 10px #d0e4f0; 40 | } 41 | 42 | #rocket { 43 | width: 5rem; 44 | height: 4.25rem; 45 | font-size: 4rem; 46 | position: absolute; 47 | bottom: 0.5rem; 48 | left: 2.5rem; 49 | } 50 | .animate { 51 | animation: jump 750ms linear; 52 | } 53 | 54 | @keyframes jump { 55 | 0% { 56 | bottom: 0; 57 | } 58 | 30% { 59 | bottom: 8rem; 60 | } 61 | 70% { 62 | bottom: 8rem; 63 | } 64 | 100% { 65 | bottom: 0; 66 | } 67 | } 68 | 69 | #car { 70 | height: 3.25rem; 71 | font-size: 3rem; 72 | filter: drop-shadow(0 1rem 0.75rem #777); 73 | position: absolute; 74 | right: 0%; 75 | bottom: 0.15rem; 76 | } 77 | 78 | @keyframes car { 79 | 0% { 80 | right: 0%; 81 | } 82 | 100% { 83 | right: 110%; 84 | } 85 | } 86 | 87 | .footer { 88 | background: seagreen; 89 | color: #ccc; 90 | font-size: 1.5rem; 91 | text-align: center; 92 | padding: 1rem; 93 | line-height: 1.5; 94 | } 95 | .footer a { 96 | text-decoration-style: wavy; 97 | color: #fff; 98 | font-weight: bold; 99 | } 100 | 101 | /* 102 | // car 103 | animation: car 4s linear infinite; 104 | */ 105 | -------------------------------------------------------------------------------- /07-clock/app.js: -------------------------------------------------------------------------------- 1 | // DOM 2 | const hourHand = document.querySelector('[data-hour-hand]'); 3 | const minHand = document.querySelector('[data-minute-hand]'); 4 | const secHand = document.querySelector('[data-second-hand]'); 5 | 6 | // SET CLOCK 7 | function setClock() { 8 | // Time 9 | const now = new Date(); 10 | const secondRatio = now.getSeconds() / 60; 11 | const minRatio = (secondRatio + now.getMinutes()) / 60; 12 | const hourRatio = (minRatio + now.getHours()) / 12; 13 | 14 | // set the rotation 15 | setRotation(secHand, secondRatio); 16 | setRotation(minHand, minRatio); 17 | setRotation(hourHand, hourRatio); 18 | } 19 | 20 | // ROTATION 21 | function setRotation(element, rotationRatio) { 22 | element.style.setProperty('--rotation', rotationRatio * 360); 23 | } 24 | 25 | setClock(); 26 | setInterval(setClock, 1000); 27 | -------------------------------------------------------------------------------- /07-clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Clock - WDS 7 | 8 | 9 | 10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /07-clock/wesbos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | WESBOS 7 | 58 | 59 | 60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | 68 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /08-movieSeat/script.js: -------------------------------------------------------------------------------- 1 | let qs = (el) => document.querySelector(el); 2 | 3 | // Get the DOM 4 | const container = qs('.container'); 5 | const seats = document.querySelectorAll('.row .seat:not(.occupied)'); 6 | const count = qs('#count'); 7 | const total = qs('#total'); 8 | const movieSelect = qs('#movie'); 9 | 10 | // Populate the UI 11 | populateUI(); 12 | 13 | let ticketPrice = +movieSelect.value; 14 | // + converts to Number // later mutation // should be after populate() 15 | 16 | // Save selected movie index and price 17 | function setMovieData(movieIndex, moviePrice) { 18 | localStorage.setItem('selectedMovieIndex', movieIndex); 19 | localStorage.setItem('selectedMoviePrice', moviePrice); 20 | } 21 | 22 | // Update the price & seat 23 | const updateSelectedCount = () => { 24 | const selectedSeats = document.querySelectorAll('.row .seat.selected'); 25 | 26 | // get the indexes of the seats -> selected 27 | // copy selected seats into a new array 28 | // map through the array 29 | // return a new array of indexes 30 | const seatsIndex = [...selectedSeats].map((seat) => 31 | [...seats].indexOf(seat) 32 | ); 33 | //console.log(seatsIndex); 34 | 35 | // localStorage 36 | localStorage.setItem('selectedSeats', JSON.stringify(seatsIndex)); 37 | 38 | // Change Values 39 | const selectedSeatsCount = selectedSeats.length; 40 | count.textContent = selectedSeatsCount; 41 | total.textContent = selectedSeatsCount * ticketPrice; 42 | 43 | setMovieData(movieSelect.selectedIndex, movieSelect.value); 44 | }; 45 | 46 | // get data from local and populate ui; 47 | function populateUI() { 48 | // getting the selected seats from the local 49 | const selectedSeats = JSON.parse(localStorage.getItem('selectedSeats')); 50 | 51 | if (selectedSeats !== null && selectedSeats.length > 0) { 52 | seats.forEach((seat, index) => { 53 | if (selectedSeats.indexOf(index) > -1) { 54 | seat.classList.add('selected'); 55 | } 56 | }); 57 | } 58 | 59 | const selectedMovieIndex = localStorage.getItem('selectedMovieIndex'); 60 | 61 | if (selectedMovieIndex !== null) { 62 | movieSelect.selectedIndex = selectedMovieIndex; 63 | } 64 | } 65 | 66 | // Event Listener for Select options of movie 67 | movieSelect.addEventListener('change', (e) => { 68 | // update ticket price based on selected seats 69 | ticketPrice = +e.target.value; 70 | 71 | // keep the options in localStorage 72 | setMovieData(e.target.selectedIndex, e.target.value); 73 | 74 | // update 75 | updateSelectedCount(); 76 | }); 77 | 78 | // Event Listener for Seat Selection 79 | container.addEventListener('click', (e) => { 80 | // check if the target has seat class 81 | if ( 82 | e.target.classList.contains('seat') && 83 | !e.target.classList.contains('occupied') 84 | ) { 85 | e.target.classList.toggle('selected'); 86 | 87 | // update the seat & price count 88 | updateSelectedCount(); 89 | } 90 | }); 91 | 92 | // initiate on page load 93 | updateSelectedCount(); 94 | -------------------------------------------------------------------------------- /08-movieSeat/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Lato&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | font-family: 'Lato', sans-serif; 11 | } 12 | 13 | main { 14 | width: 100%; 15 | height: 100vh; 16 | background-color: #242333; 17 | color: #fff; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | } 23 | 24 | h1 { 25 | text-align: center; 26 | font-size: 3em; 27 | margin-bottom: 1.5em; 28 | background: linear-gradient(45deg, #6feaf6, yellowgreen, seagreen); 29 | -webkit-background-clip: text; 30 | -webkit-text-fill-color: transparent; 31 | } 32 | 33 | .movie-container { 34 | margin: 20px 0; 35 | } 36 | 37 | .movie-container select { 38 | background-color: #fff; 39 | border: 0; 40 | border-radius: 5px; 41 | font-size: 14px; 42 | margin-left: 10px; 43 | padding: 5px 15px 5px 15px; 44 | -moz-appearance: none; 45 | -webkit-appearance: none; 46 | appearance: none; 47 | } 48 | 49 | .container { 50 | perspective: 1000px; 51 | margin-bottom: 30px; 52 | } 53 | 54 | .seat { 55 | background-color: #444451; 56 | height: 12px; 57 | width: 15px; 58 | margin: 3px; 59 | border-top-left-radius: 10px; 60 | border-top-right-radius: 10px; 61 | } 62 | 63 | .seat.selected { 64 | background-color: #6feaf6; 65 | } 66 | 67 | .seat.occupied { 68 | background-color: #fff; 69 | } 70 | 71 | .seat:nth-of-type(2) { 72 | margin-right: 18px; 73 | } 74 | 75 | .seat:nth-last-of-type(2) { 76 | margin-left: 18px; 77 | } 78 | 79 | .seat:not(.occupied):hover { 80 | cursor: pointer; 81 | transform: scale(1.2); 82 | } 83 | 84 | .showcase .seat:not(.occupied):hover { 85 | cursor: default; 86 | transform: scale(1); 87 | } 88 | 89 | .showcase { 90 | background: rgba(0, 0, 0, 0.1); 91 | padding: 5px 10px; 92 | border-radius: 5px; 93 | color: #777; 94 | list-style-type: none; 95 | display: flex; 96 | justify-content: space-between; 97 | } 98 | 99 | .showcase li { 100 | display: flex; 101 | align-items: center; 102 | justify-content: center; 103 | margin: 0 10px; 104 | } 105 | 106 | .showcase li small { 107 | margin-left: 2px; 108 | } 109 | 110 | .row { 111 | display: flex; 112 | } 113 | 114 | .screen { 115 | height: 80px; 116 | width: 100%; 117 | margin: 15px 0; 118 | transform: rotateX(-45deg); 119 | box-shadow: 0px 0px 10px #6feaf6; 120 | background-color: #ff3cac; 121 | background-image: linear-gradient( 122 | 225deg, 123 | #ff3cac 0%, 124 | #784ba0 50%, 125 | #2b86c5 100% 126 | ); 127 | } 128 | 129 | p.text { 130 | margin: 5px 0; 131 | } 132 | 133 | p.text span { 134 | color: #6feaf6; 135 | } 136 | 137 | .footer { 138 | background: #2ecc71; 139 | padding: 5px 10px; 140 | font-size: 14px; 141 | text-align: center; 142 | } 143 | .footer a { 144 | text-decoration: none; 145 | font-weight: bold; 146 | color: #266565; 147 | } 148 | -------------------------------------------------------------------------------- /09-boxShadow/app.js: -------------------------------------------------------------------------------- 1 | const qs = (el) => document.querySelector(el); 2 | 3 | const inputs = document.querySelectorAll('.controls input'); 4 | 5 | // Get & Display values 6 | function displayValue() { 7 | const radius = qs('#radius').value; 8 | const offX = qs('#off-x').value; 9 | const offY = qs('#off-y').value; 10 | const blur = qs('#blur').value; 11 | const spread = qs('#spread').value; 12 | const color = qs('#base').value; 13 | 14 | const borr = qs('.border-radius'); 15 | const boxShadow = qs('.box-shadow'); 16 | borr.innerHTML = `border-radius: ${radius}px`; 17 | boxShadow.textContent = `box-shadow: ${offX}px ${offY}px ${blur}px ${spread}px ${color};`; 18 | 19 | /* 20 | const markup = `border-radius: ${radius}px; 21 | 22 | box-shadow: ${offX}px ${offY}px ${blur}px ${spread}px ${color};`; 23 | 24 | //const mark2 = 'border-radius: ' + radius + '\n' + 'box-shadow: ' + 25 | //console.log(markup); 26 | const displ = qs('.display'); 27 | displ.textContent = markup; 28 | */ 29 | } 30 | 31 | // Handle the Update 32 | 33 | function handleUpdate() { 34 | const suffix = this.dataset.sizing || ''; 35 | //console.log(suffix); 36 | 37 | document.documentElement.style.setProperty( 38 | `--${this.name}`, 39 | this.value + suffix 40 | ); 41 | 42 | displayValue(); 43 | } 44 | 45 | inputs.forEach((input) => input.addEventListener('change', handleUpdate)); 46 | inputs.forEach((input) => input.addEventListener('mousemove', handleUpdate)); 47 | -------------------------------------------------------------------------------- /09-boxShadow/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | :root { 7 | --base: #ff0; 8 | --spread: 5px; 9 | --blur: 5px; 10 | --radius: 0px; 11 | --off-x: 0px; 12 | --off-y: 0px; 13 | 14 | font-size: 10px; 15 | } 16 | 17 | body { 18 | font-family: 'helvetica neue', sans-serif; 19 | font-size: 1.5rem; 20 | text-align: center; 21 | width: 100%; 22 | background: #fcfeff; 23 | } 24 | 25 | main { 26 | min-height: 100vh; 27 | padding: 1rem; 28 | } 29 | 30 | h2 { 31 | font-size: 3rem; 32 | margin: 2rem auto; 33 | } 34 | 35 | .controls { 36 | width: 25rem; 37 | padding: 1rem; 38 | } 39 | .controls > div { 40 | margin: 1rem 0; 41 | display: flex; 42 | align-content: center; 43 | justify-content: space-between; 44 | } 45 | 46 | input { 47 | width: 100px; 48 | margin: 0 0.5rem; 49 | } 50 | 51 | .display { 52 | border-radius: 1.5rem; 53 | background: #2691ab; 54 | box-shadow: inset 16px 16px 32px #207b91, inset -16px -16px 32px #2ca7c5; 55 | color: #ffffff; 56 | width: 30rem; 57 | min-height: 5rem; 58 | margin: 0 auto; 59 | padding: 1.5rem; 60 | text-align: left; 61 | font-size: 1.3rem; 62 | font-family: monospace; 63 | position: relative; 64 | } 65 | .display span { 66 | display: none; 67 | position: absolute; 68 | right: 0; 69 | top: 0; 70 | background: #ff0; 71 | padding: 0.5rem 1rem; 72 | border-radius: inherit; 73 | } 74 | 75 | .footer { 76 | background: #bada55; 77 | padding: 1rem; 78 | } 79 | 80 | /* 81 | For JS 82 | */ 83 | 84 | .mainBox { 85 | justify-self: center; 86 | display: grid; 87 | place-items: center; 88 | width: 85%; 89 | max-width: 50rem; 90 | height: 30rem; 91 | margin: 5rem auto; 92 | border-radius: var(--radius); 93 | box-shadow: var(--off-x) var(--off-y) var(--blur) var(--spread) var(--base); 94 | } 95 | 96 | .hl { 97 | color: var(--base); 98 | } 99 | -------------------------------------------------------------------------------- /10-flexGallery/app.js: -------------------------------------------------------------------------------- 1 | ///* 2 | const panels = Array.from(document.querySelectorAll('.panel')); 3 | 4 | function togglePanel(e) { 5 | panels.forEach((el) => el.classList.remove('open')); 6 | 7 | if (!this.className.includes('open')) { 8 | this.classList.toggle('open'); 9 | } 10 | } 11 | 12 | function toggleFlex(e) { 13 | if (e.propertyName.includes('flex')) { 14 | this.classList.toggle('open-active'); 15 | } 16 | } 17 | 18 | panels.forEach((el) => { 19 | el.addEventListener('click', togglePanel); 20 | el.addEventListener('transitionend', toggleFlex); 21 | }); 22 | //*/ 23 | -------------------------------------------------------------------------------- /10-flexGallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Flex Panels 💪 7 | 10 | 11 | 12 | 13 |
14 |
15 |

Hey

16 |

Let's

17 |

Dance

18 |
19 |
20 |

Give

21 |

Take

22 |

Receive

23 |
24 |
25 |

Experience

26 |

It

27 |

Today

28 |
29 |
30 |

Give

31 |

All

32 |

You can

33 |
34 |
35 |

Life

36 |

In

37 |

Motion

38 |
39 |
40 | 41 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /11-typeAhead/app.js: -------------------------------------------------------------------------------- 1 | const endpoint = 2 | 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; 3 | 4 | const form = document.querySelector('.search-form'); 5 | const searchInput = document.querySelector('.search'); 6 | const suggestions = document.querySelector('.suggestions'); 7 | const defaultItems = suggestions.innerHTML; 8 | 9 | const cities = []; 10 | 11 | const numFormat = new Intl.NumberFormat('en-US'); 12 | 13 | fetch(endpoint) 14 | .then((response) => response.json()) 15 | .then((data) => cities.push(...data)); 16 | 17 | /////////////////////////////// 18 | // helped from https://tfrommen.github.io/JavaScript30/06%20-%20Type%20Ahead/ 19 | function highlight(text, input) { 20 | return text.replace( 21 | new RegExp(input, 'gi'), 22 | (match) => `${match}` 23 | ); 24 | } 25 | 26 | function itemizeCity({ city, state, population }, input) { 27 | return `
  • 28 | ${highlight(city, input)}, ${highlight( 29 | state, 30 | input 31 | )} 32 | ${numFormat.format(population)} 33 |
  • `; 34 | } 35 | 36 | // Find the matching words 37 | function matchesCity({ city, state }, input) { 38 | const regex = new RegExp(input, 'i'); 39 | 40 | return regex.test(city) || regex.test(state); 41 | } 42 | 43 | function handleInput() { 44 | const input = this.value; 45 | 46 | if (input) { 47 | suggestions.innerHTML = cities 48 | .filter((city) => matchesCity(city, input)) 49 | .map((city) => itemizeCity(city, input)) 50 | .join(''); 51 | 52 | return; 53 | } 54 | 55 | suggestions.innerHTML = defaultItems; 56 | } 57 | 58 | form.addEventListener('submit', (e) => e.preventDefault()); 59 | searchInput.addEventListener('input', handleInput); 60 | 61 | /* 62 | 63 | // WES' Solution 64 | 65 | function numberWithCommas(x) { 66 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 67 | } 68 | 69 | function findMatches(wordToMatch, cities) { 70 | return cities.filter((place) => { 71 | // we figure if city or state matches with the searched 72 | const regex = new RegExp(wordToMatch, 'gi'); 73 | return place.city.match(regex) || place.state.match(regex); 74 | }); 75 | } 76 | 77 | function handleInput() { 78 | // get the data from findMatches 79 | const matchArray = findMatches(this.value, cities); 80 | 81 | const markup = matchArray 82 | .map((place) => { 83 | const regex = new RegExp(this.value, 'gi'); 84 | const cityName = place.city.replace( 85 | regex, 86 | `${this.value}` 87 | ); 88 | const stateName = place.state.replace( 89 | regex, 90 | `${this.value}` 91 | ); 92 | 93 | return ` 94 |
  • 95 | ${cityName}, ${stateName} 96 | ${numberWithCommas( 97 | place.population 98 | )} 99 |
  • 100 | `; 101 | }) 102 | .join(''); 103 | 104 | suggestions.innerHTML = markup; 105 | } 106 | 107 | */ 108 | -------------------------------------------------------------------------------- /11-typeAhead/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Type Ahead 👀 7 | 8 | 9 | 10 |
    11 |
    12 | 13 | 24 |
    25 |
    26 | 27 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /11-typeAhead/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | background: #ffc600; 4 | font-family: 'helvetica neue'; 5 | font-size: 20px; 6 | font-weight: 200; 7 | } 8 | 9 | *, 10 | *:before, 11 | *:after { 12 | box-sizing: inherit; 13 | } 14 | 15 | main { 16 | width: 100%; 17 | height: 100vh; 18 | } 19 | 20 | input { 21 | width: 100%; 22 | padding: 20px; 23 | } 24 | 25 | .search-form { 26 | max-width: 400px; 27 | width: 80%; 28 | margin: 50px auto; 29 | } 30 | 31 | input.search { 32 | margin: 0; 33 | text-align: center; 34 | outline: 0; 35 | border: 10px solid #f7f7f7; 36 | width: 120%; 37 | left: -10%; 38 | position: relative; 39 | top: 10px; 40 | z-index: 2; 41 | border-radius: 5px; 42 | font-size: 40px; 43 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19); 44 | } 45 | 46 | .suggestions { 47 | margin: 0; 48 | padding: 0; 49 | position: relative; 50 | /*perspective: 20px;*/ 51 | } 52 | 53 | .suggestions li { 54 | background: white; 55 | list-style: none; 56 | border-bottom: 1px solid #d8d8d8; 57 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.14); 58 | margin: 0; 59 | padding: 20px; 60 | transition: background 0.2s; 61 | display: flex; 62 | justify-content: space-between; 63 | text-transform: capitalize; 64 | } 65 | 66 | .suggestions li:nth-child(even) { 67 | transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001); 68 | background: linear-gradient(to bottom, #ffffff 0%, #efefef 100%); 69 | } 70 | 71 | .suggestions li:nth-child(odd) { 72 | transform: perspective(100px) rotateX(-3deg) translateY(3px); 73 | background: linear-gradient(to top, #ffffff 0%, #efefef 100%); 74 | } 75 | 76 | span.population { 77 | font-size: 15px; 78 | } 79 | 80 | .hl { 81 | background: #ffc600; 82 | } 83 | -------------------------------------------------------------------------------- /12-drawing/app.js: -------------------------------------------------------------------------------- 1 | const canvas = document.querySelector('#draw'); 2 | const ctx = canvas.getContext('2d'); 3 | 4 | // set the width & height 5 | canvas.width = window.innerWidth; 6 | canvas.height = window.innerHeight; 7 | 8 | ctx.strokeStyle = 'yellowgreen'; // starting color 9 | ctx.lineJoin = 'round'; 10 | ctx.lineCap = 'round'; // rounded line-end shape 11 | ctx.lineWidth = 25; // size of the brush 12 | 13 | // Variables that'll work later 14 | let isDrawing = false; 15 | let [lastX, lastY] = [0, 0]; // starting points 16 | let hue = 0; // for colors 17 | let direction = true; // dir for the lineWidth 18 | 19 | function draw(e) { 20 | // stop the fn if mouse isn't down | otherwise it'll paint on mousemove 21 | if (!isDrawing) return; 22 | 23 | ctx.beginPath(); 24 | ctx.moveTo(lastX, lastY); // start from 25 | ctx.lineTo(e.offsetX, e.offsetY); // go to 26 | ctx.stroke(); 27 | 28 | [lastX, lastY] = [e.offsetX, e.offsetY]; // start point are the same 29 | 30 | // add some color variation 31 | ctx.strokeStyle = `hsl(${hue}, 90%, 50%)`; 32 | hue++; 33 | if (hue >= 360) hue = 0; 34 | 35 | // flip the dir & lineWidth on condition 36 | if (ctx.lineWidth > 50 || ctx.lineWidth < 10) direction = !direction; 37 | 38 | direction == true ? ctx.lineWidth++ : ctx.lineWidth--; 39 | } 40 | 41 | // Events 42 | canvas.addEventListener('mousedown', (e) => { 43 | isDrawing = true; 44 | [lastX, lastY] = [e.offsetX, e.offsetY]; 45 | }); 46 | 47 | canvas.addEventListener('mousemove', draw); 48 | 49 | canvas.addEventListener('mouseup', () => (isDrawing = false)); 50 | canvas.addEventListener('mouseover', () => (isDrawing = false)); 51 | 52 | /* 53 | // Couldn't figure out solution for mobile devices 😞 54 | canvas.addEventListener('touchstart', (e) => { 55 | isDrawing = true; 56 | [lastX, lastY] = [e.offsetX, e.offsetY]; 57 | }); 58 | canvas.addEventListener('touchmove', draw); 59 | canvas.addEventListener('touchend', () => (isDrawing = false)); 60 | */ 61 | -------------------------------------------------------------------------------- /12-drawing/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 Canvas 6 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /13-checkboxes/app.js: -------------------------------------------------------------------------------- 1 | const boxes = document.querySelectorAll('input[type="checkbox"'); 2 | 3 | let lastChecked; // for checking the last checked checkbox 4 | 5 | function handleCheck(e) { 6 | let flag = false; // flag var for checking 7 | 8 | // IF the shiftKey = true && current el is checked 9 | if (e.shiftKey && this.checked) { 10 | // Loop over every single checkbox 11 | boxes.forEach((box) => { 12 | console.log(box); 13 | 14 | // flag = true; will check in one direction, flippin/ making opposite won't 15 | if (box === this || lastChecked === box) { 16 | flag = !flag; 17 | console.log('box s / e'); 18 | } 19 | 20 | // IF the flag is true, check the boxes 21 | if (flag) box.checked = true; 22 | }); 23 | } 24 | 25 | lastChecked = this; // assinging the last checkbox 26 | } 27 | 28 | // Main Event 29 | boxes.forEach((el) => el.addEventListener('click', handleCheck)); 30 | 31 | // clear the boxes & console 32 | document.querySelector('.clear').addEventListener('click', () => { 33 | boxes.forEach((el) => { 34 | el.checked = false; 35 | console.clear(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /13-checkboxes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hold Shift to Check Multiple Checkboxes 7 | 8 | 9 | 10 | 16 |
    17 | 18 | 19 |
    20 | 21 |

    This is an inbox layout.

    22 |
    23 |
    24 | 25 |

    Check one item

    26 |
    27 |
    28 | 29 |

    Hold down your Shift key

    30 |
    31 |
    32 | 33 |

    Check a lower item

    34 |
    35 |
    36 | 37 |

    Everything in between should also be set to checked

    38 |
    39 |
    40 | 41 |

    Try to do it without any libraries

    42 |
    43 |
    44 | 45 |

    Just regular JavaScript

    46 |
    47 |
    48 | 49 |

    Good Luck!

    50 |
    51 |
    52 | 53 |

    Don't forget to tweet your result!

    54 |
    55 |
    56 | 57 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /13-checkboxes/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 10px; 9 | } 10 | body { 11 | font-family: sans-serif; 12 | font-size: 1.5rem; 13 | width: 100%; 14 | min-height: 100vh; 15 | background: #bada55; 16 | 17 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cg fill='%239C92AC' fill-opacity='0.4'%3E%3Cpath fill-rule='evenodd' d='M0 0h4v4H0V0zm4 4h4v4H4V4z'/%3E%3C/g%3E%3C/svg%3E"); 18 | } 19 | 20 | .inbox { 21 | width: 90%; 22 | max-width: 40rem; 23 | margin: 8rem auto; 24 | background: white; 25 | border-radius: 0.5rem; 26 | box-shadow: 1rem 1rem 0 rgba(0, 0, 0, 0.1); 27 | position: relative; 28 | } 29 | 30 | .clear { 31 | cursor: pointer; 32 | background: transparent; 33 | border: 0; 34 | width: 6rem; 35 | height: 6rem; 36 | padding-bottom: 1rem; 37 | font-size: 4rem; 38 | transition: all 0.4s; 39 | filter: drop-shadow(0 0 0.75rem darkgray); 40 | 41 | position: absolute; 42 | top: 7rem; 43 | left: 17rem; 44 | transform: translateY(-100%); 45 | z-index: -1; 46 | } 47 | .inbox:hover .clear { 48 | top: 0; 49 | } 50 | 51 | .item { 52 | display: flex; 53 | align-items: center; 54 | border-bottom: 1px solid #f1f1f1; 55 | } 56 | 57 | .item:last-child { 58 | border-bottom: 0; 59 | } 60 | 61 | input:checked + p { 62 | background: linear-gradient(#dcdcdc, #f1f1f1); 63 | text-decoration: line-through; 64 | } 65 | 66 | input[type='checkbox'] { 67 | margin: 2rem; 68 | } 69 | 70 | p { 71 | margin: 0; 72 | padding: 2rem; 73 | transition: background 0.2s; 74 | flex: 1; 75 | font-family: 'helvetica neue'; 76 | font-size: 2rem; 77 | font-weight: 200; 78 | border-left: 1px solid #d1e2ff; 79 | } 80 | -------------------------------------------------------------------------------- /14-slider/app.js: -------------------------------------------------------------------------------- 1 | const slides = document.querySelectorAll('.slide'); 2 | const prevBtn = document.querySelector('.prevBtn'); 3 | const nextBtn = document.querySelector('.nextBtn'); 4 | 5 | // push each slide on left based on index 6 | slides.forEach((el, index) => (el.style.left = `${index * 100}%`)); 7 | 8 | // set a flag variable 9 | let counter = 0; 10 | 11 | prevBtn.addEventListener('click', () => { 12 | counter--; 13 | carousel(); 14 | }); 15 | nextBtn.addEventListener('click', () => { 16 | counter++; 17 | carousel(); 18 | }); 19 | 20 | function carousel() { 21 | // IF counter reaches the last slide, counter = 0 22 | if (counter === slides.length) counter = 0; 23 | 24 | // IF counter < 0, go to the last slide 25 | if (counter < 0) counter = slides.length - 1; 26 | 27 | // update transform property on each click based on counter value 28 | slides.forEach( 29 | (el) => (el.style.transform = `translateX(-${counter * 100}%)`) 30 | ); 31 | 32 | // show / hide buttons 33 | buttonHide(); 34 | } 35 | 36 | prevBtn.style.display = 'none'; 37 | function buttonHide() { 38 | // nextBtn 39 | // IF it isn't the last slide, show nextBtn, else hide 40 | if (counter < slides.length - 1) { 41 | nextBtn.style.display = 'block'; 42 | } else nextBtn.style.display = 'none'; 43 | 44 | // prevBtn 45 | // IF it's not the 1st slide, show prevBtn, else hide 46 | if (counter > 0) { 47 | prevBtn.style.display = 'block'; 48 | } else prevBtn.style.display = 'none'; 49 | } 50 | -------------------------------------------------------------------------------- /14-slider/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/14-slider/img/1.jpg -------------------------------------------------------------------------------- /14-slider/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/14-slider/img/2.jpg -------------------------------------------------------------------------------- /14-slider/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/14-slider/img/3.jpg -------------------------------------------------------------------------------- /14-slider/img/person-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/14-slider/img/person-1.jpeg -------------------------------------------------------------------------------- /14-slider/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JS Slider 7 | 8 | 9 | 10 |
    11 |
    12 |
    13 | slide image 14 |

    1

    15 |
    16 | 17 |
    18 |

    2

    19 |
    20 | 21 |
    22 |

    3

    23 |
    24 | 25 |
    26 |
    27 | slide image 32 |

    Jane Doe

    33 |

    4

    34 |
    35 |
    36 |
    37 | 38 |
    39 | 40 | 41 | 42 |
    43 |
    44 | 45 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /16-KONAMI/app.js: -------------------------------------------------------------------------------- 1 | const pressed = []; 2 | const konCode = [ 3 | 'ArrowUp', 4 | 'ArrowUp', 5 | 'ArrowDown', 6 | 'ArrowDown', 7 | 'ArrowLeft', 8 | 'ArrowRight', 9 | 'ArrowLeft', 10 | 'ArrowRight', 11 | 'b', 12 | 'a', 13 | ]; 14 | 15 | function konami(e) { 16 | pressed.push(e.key); 17 | pressed.splice(0, pressed.length - konCode.length); 18 | 19 | const [word, konWord] = [pressed.join(''), konCode.join('')]; 20 | 21 | if (word === konWord) cornify_add(); 22 | } 23 | 24 | window.addEventListener('keyup', konami); 25 | -------------------------------------------------------------------------------- /16-KONAMI/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Key Detection 7 | 8 | 12 | 64 | 65 | 66 |
    67 |

    68 | Press
    69 |
    70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 🅱 79 | 🅰 80 |

    81 |
    82 | 83 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /17-stickyNav/app.js: -------------------------------------------------------------------------------- 1 | // Wes' Code for Sticky Nav 2 | const nav = document.querySelector('#main'); 3 | let topOfNav = nav.offsetTop; 4 | 5 | function fixNav() { 6 | if (window.scrollY >= topOfNav) { 7 | document.body.style.paddingTop = nav.offsetHeight + 'px'; 8 | document.body.classList.add('fixed-nav'); 9 | } else { 10 | document.body.classList.remove('fixed-nav'); 11 | document.body.style.paddingTop = 0; 12 | } 13 | } 14 | 15 | window.addEventListener('scroll', fixNav); 16 | -------------------------------------------------------------------------------- /17-stickyNav/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 10px; 9 | } 10 | 11 | body { 12 | width: 100%; 13 | background: #eeeeee; 14 | font-family: 'helvetica neue', sans-serif; 15 | font-size: 2rem; 16 | font-weight: 1.5; 17 | } 18 | 19 | header { 20 | text-align: center; 21 | width: 100%; 22 | padding: 0 1rem; 23 | height: 50vh; 24 | background: repeating-linear-gradient( 25 | 45deg, 26 | teal, 27 | seagreen 50px, 28 | yellowgreen 30px 29 | ); 30 | 31 | display: flex; 32 | align-items: center; 33 | justify-content: center; 34 | } 35 | 36 | h1 { 37 | color: white; 38 | font-size: 7vw; 39 | text-shadow: 3px 4px 0 rgba(0, 0, 0, 0.2); 40 | } 41 | 42 | nav { 43 | background: black; 44 | width: 100%; 45 | transition: all 0.5s; 46 | position: relative; 47 | z-index: 1; 48 | } 49 | body.fixed-nav nav { 50 | position: fixed; 51 | box-shadow: 0 5px 0 rgba(0, 0, 0, 0.1); 52 | 53 | top: 0; 54 | left: 0; 55 | right: 0; 56 | } 57 | 58 | nav ul { 59 | width: 100%; 60 | min-height: 5rem; 61 | list-style: none; 62 | 63 | display: flex; 64 | flex-flow: row wrap; 65 | justify-content: center; 66 | align-items: center; 67 | } 68 | 69 | nav ul li { 70 | flex: 1; 71 | text-align: center; 72 | height: 5rem; 73 | 74 | display: grid; 75 | place-items: center; 76 | } 77 | nav ul li a { 78 | text-decoration: none; 79 | display: inline-block; 80 | padding: 1rem; 81 | color: white; 82 | transition: all 0.5s; 83 | text-transform: uppercase; 84 | border-radius: 0.5rem; 85 | } 86 | nav ul li a:hover { 87 | background: linear-gradient(45deg, seagreen, yellowgreen); 88 | } 89 | 90 | li.logo { 91 | max-width: 0; 92 | overflow: hidden; 93 | background: white; 94 | transition: all 0.5s; 95 | font-weight: 600; 96 | font-size: 3rem; 97 | border-radius: 0 0 2.5rem 0; 98 | } 99 | 100 | .fixed-nav li.logo { 101 | max-width: 500px; 102 | overflow: visible; 103 | } 104 | 105 | li.logo a { 106 | color: black; 107 | } 108 | 109 | .site-wrap { 110 | max-width: 70rem; 111 | width: 90%; 112 | margin: 7rem auto; 113 | background: white; 114 | padding: 3rem; 115 | text-align: justify; 116 | box-shadow: 0 0 10px 5px rgba(0, 0, 0, 0.05); 117 | transform: scale(0.98); 118 | transition: transform 0.5s; 119 | } 120 | body.fixed-nav .site-wrap { 121 | transform: scale(1); 122 | } 123 | 124 | .site-wrap p { 125 | margin: 1.5rem 0; 126 | } 127 | -------------------------------------------------------------------------------- /18-scrollToSlide/app.js: -------------------------------------------------------------------------------- 1 | // not made by me or wes 2 | function debounce(func, wait = 20, immediate = true) { 3 | var timeout; 4 | return function () { 5 | var context = this, 6 | args = arguments; 7 | var later = function () { 8 | timeout = null; 9 | if (!immediate) func.apply(context, args); 10 | }; 11 | var callNow = immediate && !timeout; 12 | clearTimeout(timeout); 13 | timeout = setTimeout(later, wait); 14 | if (callNow) func.apply(context, args); 15 | }; 16 | } 17 | 18 | const images = document.querySelectorAll('.slide-in'); 19 | 20 | // for each image, when it's peeking 50% then we reveal that image 21 | function checkSlide() { 22 | images.forEach((img) => { 23 | // ((scY + inHe) - img.hei) / 2 // halfway of the image 24 | const slideInAt = window.scrollY + window.innerHeight - img.height / 2; 25 | const imgBottom = img.offsetTop + img.height; 26 | 27 | const halfShown = slideInAt > img.offsetTop; 28 | const notScrolledPast = window.scrollY < imgBottom; 29 | // log these vars & scroll the page to understand 30 | 31 | halfShown && notScrolledPast 32 | ? img.classList.add('active') 33 | : img.classList.remove('active'); 34 | }); 35 | } 36 | 37 | // running checkSlide fn many times is bad for performance 38 | // so debounce will run the checkSlide once every 20ms 39 | window.addEventListener('scroll', debounce(checkSlide)); 40 | -------------------------------------------------------------------------------- /18-scrollToSlide/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 10px; 9 | } 10 | 11 | body { 12 | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 13 | font-weight: 200; 14 | font-size: 2rem; 15 | 16 | background: #cea513; 17 | background-image: linear-gradient( 18 | 45deg, 19 | rgb(33, 33, 33) 0%, 20 | transparent 59% 21 | ), 22 | repeating-linear-gradient( 23 | 45deg, 24 | rgba(168, 168, 168, 0.1) 0px, 25 | rgba(168, 168, 168, 0.1) 1px, 26 | transparent 1px, 27 | transparent 13px 28 | ), 29 | repeating-linear-gradient( 30 | 135deg, 31 | rgba(168, 168, 168, 0.1) 0px, 32 | rgba(168, 168, 168, 0.1) 1px, 33 | transparent 1px, 34 | transparent 13px 35 | ), 36 | linear-gradient(90deg, rgb(33, 33, 33), rgb(33, 33, 33)); 37 | } 38 | 39 | h1 { 40 | text-align: center; 41 | padding: 1rem 1rem 3rem 1rem; 42 | } 43 | 44 | .site-wrap { 45 | width: 90%; 46 | max-width: 70rem; 47 | margin: 10rem auto; 48 | background: white; 49 | padding: 4rem; 50 | text-align: justify; 51 | overflow: hidden; 52 | font-weight: normal; 53 | border-radius: 1rem; 54 | box-shadow: 0 0 0 0.75rem rgba(255, 255, 255, 0.15); 55 | } 56 | 57 | .site-wrap p { 58 | margin: 1rem 0; 59 | } 60 | 61 | img { 62 | max-width: 100%; 63 | padding: 1rem 0; 64 | object-fit: cover; 65 | } 66 | 67 | .align-left { 68 | float: left; 69 | margin-right: 20px; 70 | } 71 | 72 | .align-right { 73 | float: right; 74 | margin-left: 20px; 75 | } 76 | 77 | .slide-in { 78 | opacity: 0; 79 | transition: all 0.5s; 80 | } 81 | 82 | .align-left.slide-in { 83 | transform: translateX(-30%) scale(0.95); 84 | } 85 | 86 | .align-right.slide-in { 87 | transform: translateX(30%) scale(0.95); 88 | } 89 | 90 | .slide-in.active { 91 | opacity: 1; 92 | transform: translateX(0%) scale(1); 93 | } 94 | -------------------------------------------------------------------------------- /19-parallaxScroll/app.js: -------------------------------------------------------------------------------- 1 | const header = document.querySelector('header'); 2 | 3 | //vanilla 4 | 5 | window.addEventListener('scroll', () => { 6 | const scrollPos = this.scrollY; 7 | 8 | if (header.offsetHeight >= scrollPos) { 9 | header.style.backgroundSize = `${100 + scrollPos}% ${100 + scrollPos}%`; 10 | console.log(window.scrollY, header.offsetHeight); 11 | } 12 | }); 13 | 14 | // Kentaro's code with jQuery 15 | /* 16 | $(window).scroll(function () { 17 | var scrollPos = $(this).scrollTop(); 18 | $('.hero-back').css({ 19 | 'background-size': 150 + scrollPos + '%', 20 | }); 21 | }); 22 | */ 23 | -------------------------------------------------------------------------------- /19-parallaxScroll/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Parallax Scroll Effect 7 | 8 | 9 | 10 |
    11 |

    The World is Your to Conquer

    12 |
    13 | 14 |
    15 |
    16 |

    Parallax Scroll Effect

    17 | 35 |
    36 |
    37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /19-parallaxScroll/mountain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/19-parallaxScroll/mountain.jpg -------------------------------------------------------------------------------- /19-parallaxScroll/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Shadows+Into+Light&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | html { 10 | font-size: 10px; 11 | font-family: sans-serif; 12 | } 13 | 14 | body { 15 | font-size: 1.5rem; 16 | background: salmon; 17 | } 18 | 19 | header { 20 | width: 100%; 21 | height: 100vh; 22 | 23 | background: url(mountain.jpg) no-repeat; 24 | background-size: 100% 100%; 25 | background-position: center center; 26 | 27 | display: grid; 28 | justify-items: center; 29 | align-content: end; 30 | } 31 | header .front { 32 | font-family: 'Shadows Into Light', cursive; 33 | color: #fff; 34 | text-align: center; 35 | font-size: 6rem; 36 | text-shadow: -2px 2px #f38e41; 37 | font-weight: 600; 38 | width: 100%; 39 | padding-bottom: 2rem; 40 | } 41 | 42 | main { 43 | width: 100%; 44 | height: 100vh; 45 | padding: 5rem 0; 46 | background: #bada55; 47 | display: grid; 48 | place-items: center; 49 | } 50 | 51 | .site-wrap { 52 | width: 80%; 53 | margin: 0 auto; 54 | padding: 2rem; 55 | text-align: center; 56 | background: #eee; 57 | } 58 | -------------------------------------------------------------------------------- /20-localStorage/app.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector('.add-items'); 2 | const itemsList = document.querySelector('.plates'); 3 | const items = JSON.parse(localStorage.getItem('items')) || []; 4 | 5 | function addItem(e) { 6 | e.preventDefault(); 7 | 8 | const text = this.querySelector('[name="item"]').value; 9 | 10 | const item = { 11 | text, // ES6 shorthand | text = text , 12 | done: false, 13 | }; 14 | 15 | items.push(item); 16 | 17 | populateUI(items, itemsList); 18 | 19 | localStorage.setItem('items', JSON.stringify(items)); 20 | 21 | this.reset(); // reset the from 22 | } 23 | 24 | function populateUI(plates = [], platesList) { 25 | platesList.innerHTML = plates 26 | .map((plate, i) => { 27 | return ` 28 |
  • 29 | 32 | 33 | 💩 34 |
  • 35 | `; 36 | }) 37 | .join(''); // w/o join, you'll see the , of the array 38 | } 39 | 40 | function toggleDone(e) { 41 | const el = e.target; 42 | const index = el.dataset.index; 43 | 44 | // toggle the check of checkbox 45 | if (el.matches('input')) { 46 | items[index].done = !items[index].done; // flip to the opposite // true to false 47 | 48 | localStorage.setItem('items', JSON.stringify(items)); 49 | populateUI(items, itemsList); 50 | } 51 | 52 | // remove item 53 | if (el.classList.contains('close')) { 54 | items.splice(index, 1); 55 | 56 | localStorage.setItem('items', JSON.stringify(items)); 57 | populateUI(items, itemsList); 58 | } 59 | } 60 | 61 | form.addEventListener('submit', addItem); 62 | itemsList.addEventListener('click', toggleDone); 63 | 64 | // this will be invoked on page load. items will search for item in the array or return an empty array 65 | populateUI(items, itemsList); 66 | 67 | // Logics 68 | /* 69 | 1. we add item & put them in localStorage 70 | 2. on page load, we check IF the array has something in the localStorage 71 | a. IF there, populateList 72 | b. or start a new array from the empty array [] 73 | */ 74 | -------------------------------------------------------------------------------- /20-localStorage/oh-la-la.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/20-localStorage/oh-la-la.jpeg -------------------------------------------------------------------------------- /20-localStorage/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-size: 10px; 9 | font-family: Futura, 'Trebuchet MS', Arial, sans-serif; 10 | } 11 | 12 | body { 13 | text-align: center; 14 | font-size: 1.5rem; 15 | } 16 | 17 | main { 18 | background: url('oh-la-la.jpeg') center repeat; 19 | background-size: cover; 20 | min-height: 100vh; 21 | 22 | display: flex; 23 | flex-flow: column wrap; 24 | justify-content: center; 25 | align-items: center; 26 | 27 | position: relative; 28 | } 29 | 30 | .filler { 31 | position: absolute; 32 | top: 0; 33 | bottom: 0; 34 | left: 0; 35 | right: 0; 36 | width: 100%; 37 | height: 100%; 38 | background: rgba(0, 0, 0, 0.5); 39 | } 40 | 41 | svg { 42 | z-index: 1; 43 | fill: white; 44 | background: rgba(0, 0, 0, 0.1); 45 | padding: 2rem; 46 | border-radius: 50%; 47 | width: 20rem; 48 | margin-bottom: 5rem; 49 | } 50 | 51 | .wrapper { 52 | z-index: 1; 53 | padding: 2rem; 54 | width: 80%; 55 | max-width: 35rem; 56 | background: rgba(255, 255, 255, 0.95); 57 | box-shadow: 0 0 0 1rem rgba(0, 0, 0, 0.1); 58 | } 59 | 60 | h2 { 61 | text-align: center; 62 | margin: 0; 63 | font-weight: 200; 64 | } 65 | 66 | .plates { 67 | text-align: left; 68 | list-style: none; 69 | } 70 | 71 | .plates li { 72 | border-bottom: 1px solid rgba(0, 0, 0, 0.2); 73 | padding: 1rem 0; 74 | font-weight: 100; 75 | display: flex; 76 | } 77 | 78 | .plates label { 79 | flex: 1; 80 | cursor: pointer; 81 | } 82 | 83 | .plates input { 84 | display: none; 85 | } 86 | 87 | .plates input + label:before { 88 | content: '⬜️'; 89 | margin-right: 1rem; 90 | } 91 | 92 | .plates input:checked + label:before { 93 | content: '🌮'; 94 | } 95 | 96 | .add-items { 97 | margin-top: 2rem; 98 | } 99 | 100 | .add-items input { 101 | padding: 1rem; 102 | outline: 0; 103 | border: 1px solid rgba(0, 0, 0, 0.1); 104 | } 105 | 106 | .add-items input[type='submit'] { 107 | cursor: pointer; 108 | background: #ffc107; 109 | color: #333; 110 | font-weight: bold; 111 | } 112 | 113 | .close { 114 | cursor: pointer; 115 | padding-left: 0.5rem; 116 | font-size: 1.75rem; 117 | border-left: 1px solid #ffc107; 118 | } 119 | -------------------------------------------------------------------------------- /21-mouseMove/app.js: -------------------------------------------------------------------------------- 1 | const hero = document.querySelector('.hero'); 2 | const text = hero.querySelector('h1'); 3 | 4 | const walk = 25; // how far the shadow goes 5 | 6 | function shadow(e) { 7 | const { offsetWidth: width, offsetHeight: height } = hero; 8 | let { offsetX: x, offsetY: y } = e; 9 | 10 | // IF hero !== hero 11 | if (this !== e.target) { 12 | x = x + e.target.offsetLeft; 13 | y = y + e.target.offsetTop; 14 | } 15 | 16 | // walk is 100. so xWalk will be -50 || 50 17 | // (x / width * walk) - (walk / 2) 18 | const xWalk = Math.round((x / width) * walk - walk / 2); 19 | const yWalk = Math.round((y / height) * walk - walk / 2); 20 | 21 | //console.log(x, y, xWalk, yWalk); 22 | 23 | text.style.textShadow = ` 24 | ${xWalk}px ${yWalk}px 0 hsl(${xWalk * 5}, 80%, 50%), 25 | ${xWalk + 5}px ${yWalk + 5}px 0 hsl(${yWalk * 10}, 80%, 70%)`; 26 | } 27 | 28 | hero.addEventListener('mousemove', shadow); 29 | -------------------------------------------------------------------------------- /21-mouseMove/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mouse Shadow 7 | 42 | 43 | 44 |
    45 |

    46 | 🔥🔥
    47 | #JavaScript30 48 |

    49 |
    50 | 51 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /22-notable/app.js: -------------------------------------------------------------------------------- 1 | // Elements 2 | const qs = (selector) => document.querySelector(selector); 3 | 4 | const noteForm = qs('.noteForm'); 5 | const noteList = qs('.noteList'); 6 | 7 | const notes = JSON.parse(localStorage.getItem('notes')) || []; 8 | 9 | // function 10 | function addNotes(e) { 11 | e.preventDefault(); 12 | 13 | const title = this.querySelector('.title').value; 14 | const note = this.querySelector('.note').value; 15 | 16 | const noteItem = { 17 | title, 18 | note, 19 | }; 20 | 21 | notes.unshift(noteItem); 22 | 23 | populateUI(notes, noteList); 24 | localStorage.setItem('notes', JSON.stringify(notes)); 25 | 26 | this.reset(); 27 | } 28 | 29 | function populateUI(arr = [], list) { 30 | list.innerHTML = arr 31 | .map((el, i) => { 32 | return ` 33 |
  • 34 |
    35 | 36 |
    37 |

    38 | ${el.title} 39 |

    40 |

    41 | ${el.note} 42 |

    43 |
  • 44 | `; 45 | }) 46 | .join(''); // w/o join, you'll see the , of the array 47 | } 48 | 49 | function deleteNote(e) { 50 | const [el, index] = [e.target, e.target.dataset.index]; 51 | 52 | if (el.classList.contains('close')) { 53 | notes.splice(index, 1); 54 | 55 | populateUI(notes, noteList); 56 | localStorage.setItem('notes', JSON.stringify(notes)); 57 | } 58 | } 59 | 60 | // event 61 | noteForm.addEventListener('submit', addNotes); 62 | noteList.addEventListener('click', deleteNote); 63 | 64 | // on page load 65 | populateUI(notes, noteList); 66 | 67 | ///////////////////////////////////////////////////////// 68 | 69 | const openModal = qs('.openModal'); 70 | const modal = qs('.modal'); 71 | 72 | openModal.onclick = function () { 73 | modal.style.display = 'block'; 74 | }; 75 | 76 | window.onclick = function (event) { 77 | if (event.target == modal) { 78 | modal.style.display = 'none'; 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /22-notable/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Notable 7 | 8 | 9 | 12 | 13 | 14 |
    15 |
    16 |

    17 | 18 |

    Notable

    19 |

    Keep notes. Be Notable.

    20 |
    21 | 22 | 59 |
    60 | 61 | 81 | 82 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /23-sortList/app.js: -------------------------------------------------------------------------------- 1 | // table data 2 | var tableData = [ 3 | { name: 'Michael', age: '30', birthdate: '11/10/1989' }, 4 | { name: 'Mila', age: '32', birthdate: '10/1/1989' }, 5 | { name: 'Paul', age: '29', birthdate: '10/14/1990' }, 6 | { name: 'Dennis', age: '25', birthdate: '11/29/1993' }, 7 | { name: 'Tim', age: '27', birthdate: '3/12/1991' }, 8 | { name: 'Erik', age: '24', birthdate: '10/31/1995' }, 9 | ]; 10 | 11 | // set the table data 12 | function buildTable(data) { 13 | const tableBody = document.querySelector('.tableBody'); 14 | 15 | tableBody.innerHTML = tableData 16 | .map((person) => { 17 | return ` 18 | 19 | ${person.name} 20 | ${person.age} 21 | ${person.birthdate} 22 | 23 | `; 24 | }) 25 | .join(''); 26 | } 27 | 28 | // deploy the table 29 | buildTable(tableData); 30 | 31 | const th = document.querySelectorAll('th'); 32 | th.forEach((el) => el.addEventListener('click', sortTable)); 33 | 34 | // in DOM desc = descending 35 | function sortTable() { 36 | const col = this.dataset.colname; 37 | const order = this.dataset.order; 38 | const nameCapi = col.charAt(0).toUpperCase() + col.slice(1); 39 | 40 | if (col == 'birthdate') { 41 | // for date sorting 42 | 43 | if (order == 'desc') { 44 | this.dataset.order = 'asc'; 45 | this.innerHTML = `${nameCapi} ▼`; 46 | tableData = tableData.sort((a, b) => 47 | new Date(a[col]) > new Date(b[col]) ? 1 : -1 48 | ); 49 | } else { 50 | this.dataset.order = 'desc'; 51 | this.innerHTML = `${nameCapi} ▲`; 52 | tableData = tableData.sort((a, b) => 53 | new Date(a[col]) < new Date(b[col]) ? 1 : -1 54 | ); 55 | } 56 | } 57 | // string & number sorting 58 | else if (order == 'desc') { 59 | this.dataset.order = 'asc'; 60 | this.innerHTML = `${nameCapi} ▼`; 61 | tableData = tableData.sort((a, b) => (a[col] > b[col] ? 1 : -1)); 62 | } else { 63 | this.dataset.order = 'desc'; 64 | this.innerHTML = `${nameCapi} ▲`; 65 | tableData = tableData.sort((a, b) => (a[col] < b[col] ? 1 : -1)); 66 | } 67 | 68 | buildTable(tableData); 69 | } 70 | -------------------------------------------------------------------------------- /23-sortList/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sortable Table 7 | 13 | 14 | 15 | 16 | 17 |
    18 |

    Sortable Table

    19 | 20 | 21 | 22 | 25 | 28 | 31 | 32 | 33 | 34 |
    23 | Name ▲ 24 | 26 | Age ▲ 27 | 29 | Birthday ▲ 30 |
    35 |
    36 | 37 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /23-sortList/sortArticle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sort Without Articles 7 | 43 | 44 | 45 | 46 | 47 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /23-sortList/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background-image: repeating-radial-gradient( 9 | circle at center center, 10 | transparent 0px, 11 | transparent 13px, 12 | rgba(0, 0, 0, 0.03) 13px, 13 | rgba(0, 0, 0, 0.03) 24px, 14 | transparent 24px, 15 | transparent 62px, 16 | rgba(0, 0, 0, 0.03) 62px, 17 | rgba(0, 0, 0, 0.03) 96px 18 | ), 19 | repeating-radial-gradient( 20 | circle at center center, 21 | rgb(255, 255, 255) 0px, 22 | rgb(255, 255, 255) 14px, 23 | rgb(255, 255, 255) 14px, 24 | rgb(255, 255, 255) 18px, 25 | rgb(255, 255, 255) 18px, 26 | rgb(255, 255, 255) 28px, 27 | rgb(255, 255, 255) 28px, 28 | rgb(255, 255, 255) 32px 29 | ); 30 | background-size: 21px 21px; 31 | 32 | color: #333; 33 | } 34 | 35 | main { 36 | width: 100%; 37 | min-height: 100vh; 38 | } 39 | 40 | h1 { 41 | text-align: center; 42 | margin: 30px 0; 43 | } 44 | 45 | table { 46 | width: 90%; 47 | max-width: 600px; 48 | margin: 30px auto; 49 | } 50 | 51 | th { 52 | cursor: pointer; 53 | } 54 | -------------------------------------------------------------------------------- /24-jsonFetch/assets/app.js: -------------------------------------------------------------------------------- 1 | const tableBody = document.querySelector('.tbody'); 2 | let items = []; 3 | 4 | fetch('assets/projects.json') 5 | .then((response) => response.json()) 6 | .then((data) => { 7 | items.push(...data); 8 | populateUI(items, tableBody); 9 | }); 10 | 11 | function populateUI(arr = [], list) { 12 | list.innerHTML = arr 13 | .map((el, i) => { 14 | return ` 15 | 16 | ${i < 10 ? '0' + i : i} 17 | 18 | 20 | 21 | ${el.name} 22 | 23 | 24 | 25 | 26 | 28 | 29 | ${el.codeBase} 30 | 31 | 32 | 33 | ${el.notes} 34 | 35 | `; 36 | }) 37 | .join(''); 38 | } 39 | -------------------------------------------------------------------------------- /24-jsonFetch/assets/projects.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "index": 0, 4 | "name": "Weather App", 5 | "codeBase": "GitHub", 6 | "urlLive": "https://weather-td.netlify.app/", 7 | "urlCode": "https://github.com/TutulDevs/weatherApp", 8 | "notes": "API, events" 9 | }, 10 | { 11 | "index": 1, 12 | "name": "Drum Kit", 13 | "codeBase": "GitHub", 14 | "urlLive": "https://all-js.netlify.app/04-drumKit", 15 | "urlCode": "https://github.com/TutulDevs/All-JavaScript/tree/master/04-drumKit", 16 | "notes": "transitionend, audio(play, volume), PWA" 17 | }, 18 | { 19 | "index": 2, 20 | "name": "DemoLive", 21 | "codeBase": "DemoCode", 22 | "urlLive": "#", 23 | "urlCode": "#", 24 | "notes": "DemoNote" 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /25-pomodoro/app.js: -------------------------------------------------------------------------------- 1 | const start = document.querySelector('.start'); 2 | const stop = document.querySelector('.stop'); 3 | const reset = document.querySelector('.reset'); 4 | 5 | let mins = document.querySelector('.mins'); 6 | let secs = document.querySelector('.secs'); 7 | 8 | let startTimer; 9 | 10 | start.addEventListener('click', () => { 11 | if (startTimer === undefined) { 12 | startTimer = setInterval(timer, 1000); 13 | } else alert('Timer is running already!'); 14 | }); 15 | 16 | function timer() { 17 | // timer start 18 | if (secs.innerText != 0) { 19 | secs.innerText--; 20 | } else if (mins.innerText != 0 && secs.innerText == 0) { 21 | secs.innerText = 59; 22 | mins.innerText--; 23 | } 24 | 25 | // when one cycle is complete 26 | if (mins.innerText == 0 && secs.innerText == 0) { 27 | mins.innerText = 25; 28 | secs.innerText = '00'; 29 | } 30 | } 31 | 32 | ////////// Stop 33 | stop.addEventListener('click', function () { 34 | stopInterval(); 35 | startTimer = undefined; 36 | }); 37 | 38 | //Stop Timer Function 39 | function stopInterval() { 40 | clearInterval(startTimer); 41 | } 42 | 43 | ///////////// Reset 44 | reset.addEventListener('click', function () { 45 | mins.innerText = 25; 46 | secs.innerText = '00'; 47 | 48 | stopInterval(); 49 | startTimer = undefined; 50 | }); 51 | -------------------------------------------------------------------------------- /25-pomodoro/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | 8 | html { 9 | font-family: 'Open Sans', sans-serif; 10 | font-size: 10px; 11 | } 12 | 13 | body { 14 | background-color: #77aa77; 15 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 2 1'%3E%3Cdefs%3E%3ClinearGradient id='a' gradientUnits='userSpaceOnUse' x1='0' x2='0' y1='0' y2='1'%3E%3Cstop offset='0' stop-color='%2377aa77'/%3E%3Cstop offset='1' stop-color='%234fd'/%3E%3C/linearGradient%3E%3ClinearGradient id='b' gradientUnits='userSpaceOnUse' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23cf8' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='%23cf8' stop-opacity='1'/%3E%3C/linearGradient%3E%3ClinearGradient id='c' gradientUnits='userSpaceOnUse' x1='0' y1='0' x2='2' y2='2'%3E%3Cstop offset='0' stop-color='%23cf8' stop-opacity='0'/%3E%3Cstop offset='1' stop-color='%23cf8' stop-opacity='1'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect x='0' y='0' fill='url(%23a)' width='2' height='1'/%3E%3Cg fill-opacity='0.5'%3E%3Cpolygon fill='url(%23b)' points='0 1 0 0 2 0'/%3E%3Cpolygon fill='url(%23c)' points='2 1 2 0 0 0'/%3E%3C/g%3E%3C/svg%3E"); 16 | background-attachment: fixed; 17 | background-size: cover; 18 | 19 | font-size: 1.6rem; 20 | line-height: 120%; 21 | } 22 | 23 | main { 24 | width: 100%; 25 | height: 100vh; 26 | display: grid; 27 | place-items: center; 28 | } 29 | 30 | .timer-box { 31 | width: 90%; 32 | max-width: 50rem; 33 | min-height: 30rem; 34 | } 35 | 36 | .timer-main { 37 | width: 20rem; 38 | height: 20rem; 39 | margin: 2rem auto; 40 | border-radius: 50%; 41 | background: #7be6a6; 42 | position: relative; 43 | box-shadow: 0 0 1rem 0px rgb(77 240 203); 44 | } 45 | 46 | .timer-overlay { 47 | position: absolute; 48 | top: 1rem; 49 | bottom: 1rem; 50 | left: 1rem; 51 | right: 1rem; 52 | width: 18rem; 53 | height: 18rem; 54 | border-radius: 50%; 55 | background: #7be4a6; 56 | box-shadow: inset 6px 6px 20px #6fcd95, inset -6px -6px 20px #87fbb7; 57 | font-size: 4.5rem; 58 | font-weight: 400; 59 | display: grid; 60 | gap: 0.5rem; 61 | grid-auto-flow: column; 62 | justify-content: center; 63 | align-items: center; 64 | } 65 | 66 | .controls { 67 | min-height: 10rem; 68 | display: grid; 69 | gap: 2rem; 70 | grid-auto-flow: column; 71 | justify-content: center; 72 | align-items: center; 73 | } 74 | 75 | button { 76 | cursor: pointer; 77 | background: transparent; 78 | padding: 1.25rem; 79 | border: 0; 80 | border-radius: 30%; 81 | transition: all 0.3s; 82 | display: grid; 83 | place-items: center; 84 | } 85 | 86 | button svg { 87 | transform: scale(1.5); 88 | transition: all 0.3s; 89 | } 90 | button:hover svg { 91 | transform: scale(1.75); 92 | } 93 | -------------------------------------------------------------------------------- /26-followLinks/app.js: -------------------------------------------------------------------------------- 1 | // select all the links, that need to track 2 | const allLinks = document.querySelectorAll('a'); 3 | 4 | // create a highlight element 5 | const highlight = document.createElement('span'); 6 | highlight.classList.add('highlight'); 7 | document.body.append(highlight); 8 | 9 | function followLink() { 10 | // get coordinates of links 11 | const linkCoords = this.getBoundingClientRect(); 12 | 13 | // get coords based on scroll X Y 14 | const coords = { 15 | width: linkCoords.width, 16 | height: linkCoords.height, 17 | top: linkCoords.top + window.scrollY, 18 | left: linkCoords.left + window.scrollX, 19 | }; 20 | //console.log(coords); 21 | 22 | // now add style to css 23 | highlight.style.width = `${coords.width}px`; 24 | highlight.style.height = `${coords.height}px`; 25 | highlight.style.transform = `translate(${coords.left}px, ${coords.top}px)`; 26 | } 27 | 28 | // on mouseenter 29 | allLinks.forEach((a) => a.addEventListener('mouseenter', followLink)); 30 | -------------------------------------------------------------------------------- /26-followLinks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 👀👀👀Follow Along Nav 7 | 8 | 9 | 10 |
    11 |

    Follow Along Links

    12 | 13 | 22 | 23 |
    24 |

    25 | Lorem ipsum dolor sit amet, 26 | consectetur adipisicing elit. Est 27 | explicabo unde natus necessitatibus esse 28 | obcaecati distinctio, aut itaque, qui vitae! 29 |

    30 |

    31 | Aspernatur sapiente quae sint soluta modi, 32 | atque praesentium laborum pariatur earum 33 | quaerat cupiditate consequuntur facilis ullam 34 | dignissimos, aperiam quam veniam. 35 |

    36 |

    37 | Cum ipsam quod, incidunt sit ex 38 | tempore placeat maxime 39 | corrupti possimus 40 | veritatis ipsum fugit recusandae est 41 | doloremque? Hic, quibusdam, nulla. 42 |

    43 |

    44 | Esse quibusdam, ad, ducimus cupiditate nulla, 45 | quae magni odit totam ut consequatur eveniet 46 | sunt quam provident sapiente dicta neque quod. 47 |

    48 |

    49 | Aliquam dicta sequi culpa fugiat 50 | consequuntur pariatur optio ad minima, maxime 51 | odio, distinctio magni impedit tempore enim 52 | repellendus repudiandae quas! 53 |

    54 |
    55 |
    56 | 57 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /26-followLinks/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | min-height: 100vh; 9 | font-family: sans-serif; 10 | background: linear-gradient( 11 | 45deg, 12 | hsla(340, 100%, 55%, 1) 0%, 13 | hsla(340, 100%, 55%, 0) 70% 14 | ), 15 | linear-gradient( 16 | 135deg, 17 | hsla(225, 95%, 50%, 1) 10%, 18 | hsla(225, 95%, 50%, 0) 80% 19 | ), 20 | linear-gradient( 21 | 225deg, 22 | hsla(140, 90%, 50%, 1) 10%, 23 | hsla(140, 90%, 50%, 0) 80% 24 | ), 25 | linear-gradient( 26 | 315deg, 27 | hsla(35, 95%, 55%, 1) 100%, 28 | hsla(35, 95%, 55%, 0) 70% 29 | ); 30 | } 31 | 32 | h1 { 33 | color: #fff; 34 | text-align: center; 35 | margin-top: 50px; 36 | } 37 | 38 | .wrapper { 39 | margin: 0 auto; 40 | padding: 20px; 41 | max-width: 500px; 42 | font-size: 20px; 43 | line-height: 2; 44 | text-align: justify; 45 | position: relative; 46 | } 47 | 48 | a { 49 | text-decoration: none; 50 | color: black; 51 | background: rgba(0, 0, 0, 0.05); 52 | border-radius: 20px; 53 | } 54 | 55 | .highlight { 56 | transition: all 0.35s; 57 | border-bottom: 1px solid crimson; 58 | position: absolute; 59 | top: 0; 60 | background: white; 61 | left: 0; 62 | z-index: -1; 63 | border-radius: 25px; 64 | display: block; 65 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 66 | } 67 | 68 | .menu { 69 | list-style: none; 70 | display: flex; 71 | flex-flow: row wrap; 72 | justify-content: space-evenly; 73 | align-content: center; 74 | margin: 50px 0; 75 | } 76 | 77 | .menu a { 78 | display: inline-block; 79 | padding: 5px; 80 | margin: 20px; 81 | color: black; 82 | } 83 | -------------------------------------------------------------------------------- /27-dragDrop/app.js: -------------------------------------------------------------------------------- 1 | // Elements 2 | const items = document.querySelectorAll('.item'); 3 | const dropzone = document.querySelector('.dropzone'); 4 | 5 | // make draggable true dynamically | draggable="true" 6 | items.forEach(el=>el.draggable = true); 7 | 8 | // Functions 9 | function onDragStart(e) { 10 | // for draggin into new parent we need dataTransfer & setData 11 | e.dataTransfer.setData('text/plain', e.target.id); 12 | 13 | // style while draggin 14 | e.currentTarget.style.borderColor = 'teal'; 15 | } 16 | 17 | function onDragOver(e) { 18 | e.preventDefault(); 19 | } 20 | 21 | function onDrop(e) { 22 | e.preventDefault(); 23 | //get the data that we set 24 | const id = e.dataTransfer.getData('text'); 25 | 26 | // select the draggable el 27 | const draggableEl = document.getElementById(id); 28 | draggableEl.style.borderColor = 'salmon'; 29 | 30 | // appen our draggableEl to the zone 31 | this.appendChild(draggableEl); 32 | 33 | // reset dataTransfer obj 34 | e.dataTransfer.clear(); 35 | } 36 | 37 | 38 | // Events 39 | items.forEach(item => item.addEventListener('dragstart', onDragStart)); 40 | dropzone.addEventListener('dragover', onDragOver); 41 | dropzone.addEventListener('drop', onDrop); 42 | -------------------------------------------------------------------------------- /27-dragDrop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Drag & Drop 8 | 9 | 10 | 11 | 12 |
    13 |

    Food & Drinks Buffet

    14 |

    15 | Enrich Your Platter 16 |

    17 |
    18 |
    19 |
    20 |
    21 | 🍗 22 |
    23 |
    24 | 🍖 25 |
    26 |
    27 | 🍔 28 |
    29 |
    30 | 🍨 31 |
    32 |
    33 | 🥯 34 |
    35 |
    36 | 🍜 37 |
    38 |
    39 | 🍱 40 |
    41 |
    42 | 🍰 43 |
    44 |
    45 | 🍻 46 |
    47 |
    48 | 🍩 49 |
    50 |
    51 | 🍸 52 |
    53 |
    54 | ☕ 55 |
    56 |
    57 | 🍝 58 |
    59 |
    60 | 🍤 61 |
    62 |
    63 | 64 |
    65 |
    66 | 67 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /27-dragDrop/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Big+Shoulders+Inline+Text:wght@600&family=Open+Sans:ital,wght@0,300;1,300&display=swap'); 2 | 3 | 4 | 5 | 6 | * { 7 | margin: 0; 8 | padding: 0; 9 | box-sizing: border-box; 10 | } 11 | html { 12 | font-size: 10px; 13 | font-family: 'Open Sans', sans-serif; 14 | } 15 | body { 16 | width: 100%; 17 | min-height: 100vh; 18 | font-size: 1.5rem; 19 | background: linear-gradient(-90deg, #E76F51, #F77F00); 20 | } 21 | 22 | 23 | 24 | header { 25 | width: 100%; 26 | min-height: 20vh; 27 | margin-bottom: 3rem; 28 | padding: 3rem 1rem; 29 | text-align: center; 30 | color: #fff; 31 | } 32 | 33 | header h2 { 34 | margin-bottom: 1rem; 35 | font-size: 4.5rem; 36 | font-weight: 600; 37 | transform: skewX(-20deg); 38 | font-family: 'Big Shoulders Inline Text', cursive; 39 | } 40 | header p { 41 | font-size: 2rem; 42 | font-weight: 300; 43 | font-style: italic; 44 | } 45 | 46 | main { 47 | width: 100%; 48 | min-height: 80vh; 49 | padding: 2rem; 50 | display: grid; 51 | gap: 4rem 2rem; 52 | grid-template-columns: repeat(auto-fit, minmax(25rem, 1fr)); 53 | align-content: center; 54 | } 55 | 56 | .item-zone, 57 | .dropzone { 58 | background: linear-gradient(118deg,#F4A261, #E9C46A); 59 | min-height: 10rem; 60 | padding: 1rem; 61 | border-radius: 0 2rem 2rem; 62 | position: relative; 63 | display: flex; 64 | align-items: center; 65 | justify-content: center; 66 | flex-flow: row wrap; 67 | } 68 | 69 | .item-zone::before, 70 | .dropzone::before { 71 | position: absolute; 72 | top: -2.5rem; 73 | left: 0; 74 | width: 50%; 75 | height: 2rem; 76 | padding: 0.25rem 0; 77 | padding-left: 1.5rem; 78 | background: linear-gradient(-118deg,#F4A261, #E9C46A); 79 | color: #fff; 80 | border-top-left-radius: 2rem; 81 | clip-path: polygon(0 0, 88% 0, 100% 100%, 0% 100%); 82 | } 83 | .item-zone::before { 84 | content: 'Pick one️'; 85 | } 86 | .dropzone::before { 87 | content: 'Drop️'; 88 | } 89 | 90 | .item { 91 | font-size: 2.75rem; 92 | border: 1px solid #E9ECEF; 93 | border-radius: 1rem; 94 | padding: 1.25rem; 95 | margin: 0.5rem; 96 | filter: drop-shadow(0rem 0 0.75rem gold); 97 | } 98 | 99 | p.footer { 100 | text-align: center; 101 | padding: 1rem; 102 | } 103 | p.footer a { 104 | text-decoration: none; 105 | color: #fff; 106 | } -------------------------------------------------------------------------------- /28-bmiCalc/app.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector('form'); 2 | 3 | // Get the BMI 4 | function getBMI(e) { 5 | e.preventDefault(); 6 | 7 | const weight = document.querySelector('#weight').value; 8 | let height = document.querySelector('#height').value; 9 | const result = document.querySelector('.result'); 10 | 11 | const bmi = (weight / height / height) * 10000; 12 | 13 | result.textContent = 'Your BMI is: ' + Math.round(bmi); 14 | } 15 | 16 | 17 | // Events 18 | form.addEventListener('submit', getBMI); -------------------------------------------------------------------------------- /28-bmiCalc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BMI Calculator 7 | 8 | 9 | 10 |
    11 |
    12 |
    13 | 14 | 15 |
    16 | 17 |
    18 | 19 | 20 |
    21 |
    22 |

    Your BMI is: 00

    23 |
    24 |
    25 | 26 |
    27 |
    28 |
    29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /28-bmiCalc/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; padding: 0; 3 | box-sizing: border-box; 4 | } 5 | 6 | html { 7 | font-size: 10px; 8 | font-family: Sans-Serif; 9 | } 10 | 11 | body { 12 | width: 100%; 13 | height: 100vh; 14 | background: #bada55; 15 | font-size: 1.6rem; 16 | } 17 | 18 | main { 19 | width: 100%; 20 | height: 100vh; 21 | display: grid; 22 | place-items: center; 23 | } 24 | 25 | form { 26 | width: 90%; 27 | max-width: 30rem; 28 | min-height: 40rem; 29 | } 30 | 31 | form div { 32 | height: 5rem; 33 | margin: 1rem auto; 34 | display: grid; 35 | gap: 1rem; 36 | grid-auto-flow: column; 37 | place-items: center; 38 | } 39 | 40 | input, button { 41 | padding: 1rem; 42 | border: 0; 43 | border-radius: 1rem; 44 | } 45 | 46 | .btn { 47 | background: coral; 48 | color: #fff; 49 | width: 10rem; 50 | } -------------------------------------------------------------------------------- /29-currencyConvert/app.js: -------------------------------------------------------------------------------- 1 | const curEl_one = document.getElementById('currency-one'); 2 | const amountEl_one = document.getElementById('amount-one'); 3 | const curEl_two = document.getElementById('currency-two'); 4 | const amountEl_two = document.getElementById('amount-two'); 5 | 6 | const rateEl = document.getElementById('rate'); 7 | const swap = document.getElementById('swap'); 8 | 9 | // function 10 | function calculate() { 11 | // get the select options value 12 | const curOneVal = curEl_one.value; 13 | const curTwoVal = curEl_two.value; 14 | 15 | // fetch the data of selected currencyEl_one 16 | fetch(`https://api.exchangerate-api.com/v4/latest/${curOneVal}`) 17 | .then(res => res.json()) 18 | .then(data => { 19 | 20 | //console.log(data); 21 | const rate = data.rates[curTwoVal]; 22 | 23 | rateEl.innerText = `1 ${curOneVal} = ${rate.toFixed(4)} ${curTwoVal}`; 24 | 25 | amountEl_two.value = (amountEl_one.value * rate).toFixed(2); 26 | }); 27 | }; 28 | 29 | // Event listeners 30 | curEl_one.addEventListener('change', calculate); 31 | curEl_two.addEventListener('change', calculate); 32 | 33 | amountEl_one.addEventListener('input', calculate); 34 | amountEl_two.addEventListener('input', calculate); 35 | 36 | 37 | // Swap the values; 38 | swap.addEventListener('click', () => { 39 | const temp = curEl_one.value; 40 | curEl_one.value = curEl_two.value; 41 | curEl_two.value = temp; 42 | 43 | calculate(); 44 | }); 45 | 46 | // calculate on page load 47 | calculate(); -------------------------------------------------------------------------------- /29-currencyConvert/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-color: #5fbaa7; 3 | } 4 | 5 | * { 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | background-color: #f4f4f4; 11 | font-family: Arial, Helvetica, sans-serif; 12 | display: flex; 13 | flex-direction: column; 14 | align-items: center; 15 | justify-content: center; 16 | min-height: 100vh; 17 | margin: 0; 18 | padding: 20px; 19 | 20 | background-color: #f6e0e7; 21 | background-image: linear-gradient(315deg, #f6e0e7 0%, #c6dbdb 100%); 22 | 23 | } 24 | 25 | h1 { 26 | color: var(--primary-color); 27 | } 28 | 29 | p { 30 | text-align: center; 31 | } 32 | 33 | .btn { 34 | color: #fff; 35 | background: var(--primary-color); 36 | cursor: pointer; 37 | border: 0; 38 | border-radius: 5px; 39 | font-size: 15px; 40 | padding: 8px 12px; 41 | } 42 | 43 | 44 | .currency { 45 | padding: 40px 0; 46 | display: flex; 47 | align-items: center; 48 | justify-content: space-between; 49 | } 50 | 51 | .currency select { 52 | padding: 10px 20px 10px 10px; 53 | -moz-appearance: none; 54 | -webkit-appearance: none; 55 | appearance: none; 56 | border: 1px solid #dedede; 57 | font-size: 16px; 58 | /* You may not need these following lines. The arrow did not show for me on MacOS/Chrome so I added it. Just remove it if you would like */ 59 | background: transparent; 60 | background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%20000002%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'); 61 | background-position: right 10px top 50%, 0, 0; 62 | background-size: 12px auto, 100%; 63 | background-repeat: no-repeat; 64 | } 65 | 66 | .currency input { 67 | border: 0; 68 | background: transparent; 69 | font-size: 30px; 70 | text-align: right; 71 | } 72 | 73 | .swap-rate-container { 74 | display: flex; 75 | align-items: center; 76 | justify-content: space-between; 77 | } 78 | 79 | .rate { 80 | color: var(--primary-color); 81 | font-size: 14px; 82 | padding: 0 10px; 83 | } 84 | 85 | select:focus, 86 | input:focus, 87 | button:focus { 88 | outline: 0; 89 | } 90 | 91 | @media (max-width: 600px) { 92 | .currency input { 93 | width: 200px; 94 | } 95 | } -------------------------------------------------------------------------------- /30-articlePrev/app.js: -------------------------------------------------------------------------------- 1 | const toggle = document.querySelector(".toggle-icon"); 2 | const shareBox = document.querySelector(".shareBox"); 3 | 4 | function toggleBox(e) { 5 | const el = e.target.dataset.toggle; 6 | 7 | if (el === "up") { 8 | e.target.dataset.toggle = "down"; 9 | shareBox.style.transform = "translateY(0%)"; 10 | } else if (el === "down") { 11 | e.target.dataset.toggle = "up"; 12 | shareBox.style.transform = "translateY(100%)"; 13 | } 14 | } 15 | 16 | toggle.addEventListener("click", toggleBox); 17 | -------------------------------------------------------------------------------- /30-articlePrev/img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/30-articlePrev/img/avatar.jpg -------------------------------------------------------------------------------- /30-articlePrev/img/drawers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/30-articlePrev/img/drawers.jpg -------------------------------------------------------------------------------- /30-articlePrev/img/fb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /30-articlePrev/img/pt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /30-articlePrev/img/share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /30-articlePrev/img/tw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /30-articlePrev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Article Preview Component 7 | 8 | 9 | 10 |
    11 | 12 |
    13 | drawers 14 | 15 |
    16 |

    17 | Shift the overall look and feel by adding these wonderful touches to furniture in your home 18 |

    19 |

    20 | Ever been in a room and felt like something was missing? Perhaps it felt slightly bare and uninviting. I’ve got some simple tips to help you make any room feel complete. 21 |

    22 |
    23 | 24 |
    25 |
    26 | avatar 27 |
    28 |

    Michelle Appleton

    29 |

    28 July 2020

    30 |
    31 |
    32 | 33 |
    34 | share icon 35 |
    36 |
    37 | 38 |
    39 |
    40 |

    Share

    41 | fb icon 42 | twitter icon 43 | pinterest icon 44 |
    45 | 46 |
    47 |
    48 |
    49 | 50 |
    51 |

    52 | Project idea is provided by Frontendmentor.
    53 | See my all JavaScript Projects. 54 |

    55 | 56 | 57 | -------------------------------------------------------------------------------- /30-articlePrev/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Manrope:wght@500;700&display=swap"); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | html { 9 | font-size: 10px; 10 | font-family: "Manrope", "sans-serif"; 11 | } 12 | body { 13 | color: #333; 14 | background-color: hsl(210, 46%, 95%); 15 | font-size: 1.5rem; 16 | line-height: 1.3; 17 | } 18 | img { 19 | display: inline-block; 20 | max-width: 100%; 21 | object-fit: cover; 22 | } 23 | 24 | main { 25 | width: 100%; 26 | min-height: 100vh; 27 | display: grid; 28 | place-items: center; 29 | } 30 | 31 | .card { 32 | width: 90%; 33 | max-width: 30rem; 34 | min-height: 30rem; 35 | margin: 5rem 0; 36 | background: #fff; 37 | border-radius: 0.75rem; 38 | box-shadow: 0 0.5rem 5rem rgba(0, 0, 0, 0.2); 39 | overflow: hidden; 40 | 41 | position: relative; 42 | } 43 | .hero { 44 | width: 100%; 45 | height: 20rem; 46 | } 47 | 48 | article { 49 | padding: 3rem 2rem; 50 | } 51 | .description { 52 | margin-top: 2rem; 53 | color: #777; 54 | } 55 | 56 | .bottom, 57 | .shareBox { 58 | padding: 1rem 2rem; 59 | height: 8rem; 60 | display: flex; 61 | justify-content: space-between; 62 | align-items: center; 63 | } 64 | .bottom .right { 65 | background: lightgray; 66 | border-radius: 50%; 67 | padding: 0.5rem 0.75rem; 68 | z-index: 10; 69 | } 70 | .bottom .left { 71 | display: flex; 72 | } 73 | .avatar { 74 | width: 5rem; 75 | margin-right: 1rem; 76 | border-radius: 50%; 77 | } 78 | 79 | .shareBox { 80 | background: #44535e; 81 | position: absolute; 82 | bottom: 0; 83 | width: 100%; 84 | transform: translateY(100%); 85 | transition: all 0.5s; 86 | } 87 | .shareBox .left { 88 | flex: 3; 89 | display: flex; 90 | align-items: center; 91 | } 92 | .shareBox .left h2 { 93 | color: lightgray; 94 | display: inline-block; 95 | margin-right: 1rem; 96 | } 97 | .shareBox .left img { 98 | margin: 0 0.5rem; 99 | } 100 | .shareBox .right { 101 | flex: 1; 102 | } 103 | 104 | .credit { 105 | text-align: center; 106 | padding: 1rem; 107 | font-size: 1.3rem; 108 | } 109 | .credit a { 110 | text-decoration: none; 111 | color: teal; 112 | } 113 | -------------------------------------------------------------------------------- /31-faqAccordion/app.js: -------------------------------------------------------------------------------- 1 | const btns = document.querySelectorAll('.acc-btn'); 2 | 3 | // fn 4 | function accordion() { 5 | // this = the btn | icon & bg changed 6 | this.classList.toggle('is-open'); 7 | 8 | // the acc-content 9 | const content = this.nextElementSibling; 10 | 11 | // IF open, close | else open 12 | if (content.style.maxHeight) content.style.maxHeight = null; 13 | else content.style.maxHeight = content.scrollHeight + 'px'; 14 | } 15 | 16 | // event 17 | btns.forEach(el => el.addEventListener('click', accordion)); -------------------------------------------------------------------------------- /31-faqAccordion/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | html { 7 | font-family: sans-serif; 8 | font-size: 10px; 9 | } 10 | body { 11 | width: 100%; 12 | min-height: 100vh; 13 | font-size: 1.6rem; 14 | line-height: 140%; 15 | background-color: #f3f6f6; 16 | opacity: 0.3; 17 | background-image: repeating-radial-gradient(circle at 0 0, transparent 0, #f3f6f6 50px ), repeating-linear-gradient( #56d1b355, #56d1b3 ); 18 | opacity: 1; 19 | display: grid; 20 | place-items: center; 21 | } 22 | .card { 23 | background: #fff; 24 | color: #333; 25 | margin: 15rem auto; 26 | width: 90%; 27 | max-width: 50rem; 28 | min-height: 30rem; 29 | border-radius: 2rem; 30 | } 31 | 32 | .hero { 33 | display: flex; 34 | justify-content: center; 35 | transform: translateY(-55%); 36 | } 37 | .hero .img { 38 | filter: drop-shadow(0rem 1.5rem rgba(0,0,0,0.1)); 39 | transition: 0.3s ease-out; 40 | } 41 | .card:hover .img { 42 | filter: drop-shadow(0rem 2.5rem rgba(0,0,0,0.1)); 43 | } 44 | 45 | .title { 46 | text-align: center; 47 | font-size: 5rem; 48 | padding: 1rem; 49 | } 50 | 51 | .acc-container { 52 | padding: 4rem 2rem; 53 | } 54 | .acc-btn { 55 | width: 100%; 56 | padding: 1.6rem 2rem; 57 | font-size: 1.6rem; 58 | cursor: pointer; 59 | background: inherit; 60 | border: none; 61 | outline: none; 62 | text-align: left; 63 | transition: all 0.5s linear; 64 | } 65 | .acc-btn:after { 66 | content: "\27A4"; 67 | color: #fa8d0c; 68 | float: right; 69 | transition: all 0.3s linear; 70 | } 71 | .acc-btn.is-open:after { 72 | transform: rotate(90deg); 73 | } 74 | .acc-btn:hover, .acc-btn.is-open { 75 | color: #000; 76 | font-weight: bold; 77 | } 78 | 79 | .acc-content { 80 | max-height: 0; 81 | color: rgba(0,0,0,0.75); 82 | font-size: 1.5rem; 83 | margin: 0 2rem; 84 | padding-left: 1rem; 85 | overflow: hidden; 86 | transition: max-height 0.3s ease-in-out; 87 | border-bottom: 1px solid #ccc; 88 | } 89 | 90 | .credit { 91 | text-align: center; 92 | padding: 1rem; 93 | } 94 | .credit a { 95 | text-decoration: wavyunderline; 96 | color: dodgerblue; 97 | } -------------------------------------------------------------------------------- /33-contactList/app.js: -------------------------------------------------------------------------------- 1 | // The people 2 | const people = [{ 3 | name: 'John Doe', 4 | url: 'https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_960_720.png' 5 | }, 6 | { 7 | name: 'Jonas Schmedtmann', 8 | url: '#' 9 | }, 10 | { 11 | name: 'Alex Xander', 12 | url: 'https://placekitten.com/100/100' 13 | }, 14 | { 15 | name: 'Peter File Norton', 16 | url: '#' 17 | }, 18 | { 19 | name: 'Callum', 20 | url: '#' 21 | }, 22 | { 23 | name: 'Carla Sandison', 24 | url: 'https://placekitten.com/80/80' 25 | }, 26 | { 27 | name: 'Mr. You', 28 | url: 'https://placekitten.com/90/90' 29 | }, 30 | ]; 31 | // UI function 32 | function populateUI(peopleList, arr = []) { 33 | peopleList.innerHTML = arr.map((people, i) => { 34 | return ` 35 |
    36 |
    37 | ${people.name} 38 |
    39 |

    ${people.name}

    40 |
    41 | ` 42 | }).join('') 43 | } 44 | 45 | // Initials 46 | function initials(name) { 47 | return name.split(' ').map(n => n[0]).splice(0, 2).join(''); 48 | } 49 | //console.log(initials('John Doe Superstar')) // JD 50 | 51 | 52 | // Get the result in the UI 53 | const list = document.querySelector('.list'); 54 | populateUI(list, people); 55 | 56 | 57 | // select images w/o URL 58 | const images = document.querySelectorAll('img[src="#"]'); 59 | images.forEach(img => img.parentElement.textContent = initials(img.alt)); -------------------------------------------------------------------------------- /33-contactList/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | User Avatar 8 | 9 | 10 | 11 | 12 |
    13 |
    14 |

    15 |

    Contacts

    16 |

    🔍

    17 |
    18 | 19 |
    20 | 26 |
    27 | 28 |
    29 | 30 |

    31 | Built by Tutul.
    32 | See my other JS projects. 33 |

    34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /33-contactList/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | html { 8 | font-family: 'Lato', sans-serif; 9 | font-size: 10px; 10 | } 11 | body { 12 | font-size: 1.6rem; 13 | color: #333; 14 | display: grid; 15 | gap: 1rem; 16 | place-items: center; 17 | 18 | background-image: repeating-linear-gradient(45deg, rgba(0,0,0,0.05) 0px, rgba(0,0,0,0.05) 2px,transparent 2px, transparent 4px),linear-gradient(0deg, rgb(70, 143, 234),rgb(187, 235, 205)); 19 | } 20 | main { 21 | background: #eee; 22 | width: 90%; 23 | max-width: 40rem; 24 | min-height: 100vh; 25 | margin: 5rem 0; 26 | box-shadow: 0 0.75rem 1.5rem #ccc; 27 | border-radius: 0.75rem; 28 | display: flex; 29 | flex-flow: column wrap; 30 | } 31 | 32 | header { 33 | background: #eee; 34 | height: 7.5rem; 35 | margin-bottom: 2rem; 36 | padding: 0 1rem; 37 | box-shadow: 0 1rem 1rem #ddd; 38 | color: #858585; 39 | border-radius: 0.75rem 0.75rem 0 0; 40 | display: flex; 41 | justify-content: space-between; 42 | align-items: center; 43 | } 44 | header p { 45 | font-size: 2.25rem; 46 | opacity: 0.5; 47 | } 48 | 49 | section { 50 | margin: 1rem 0; 51 | padding: 0 1rem; 52 | display: flex; 53 | align-items: center; 54 | } 55 | section h2 { 56 | font-size: 2.25rem; 57 | font-weight: 400; 58 | } 59 | .img-box { 60 | border: 2px solid #add; 61 | margin-right: 2rem; 62 | width: 6rem; 63 | height: 6rem; 64 | border-radius: 50%; 65 | font-weight: 400; 66 | font-size: 2rem; 67 | display: grid; 68 | place-items: center; 69 | } 70 | .img-box img { 71 | width: 95%; 72 | height: 95%; 73 | object-fit: cover; 74 | border-radius: inherit; 75 | } 76 | 77 | p.credit { 78 | text-align: center; 79 | padding: 1rem; 80 | color: #fff; 81 | } -------------------------------------------------------------------------------- /34-darkMode/fixGradTrans.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Fix Gradient Transition 9 | 115 | 116 | 117 | 118 |
    119 |

    120 | Logo 121 |

    122 | 125 |
    126 | 127 |
    128 |

    129 | Fix CSS transition on gradient background 130 |

    131 | 132 | Tutorial 133 | 134 |
    135 | 136 | 141 | 142 | 143 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /34-darkMode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dark Mode 8 | 9 | 10 | 11 | 12 |
    13 |

    14 | Logo 15 |

    16 | 19 |
    20 | 21 |
    22 |

    23 | Toggle dark mode with one line of JavaScript 😎 24 |

    25 | 26 | Tutorial 27 | 28 |
    29 | 30 | 35 | 36 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /34-darkMode/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;500&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | body { 8 | width: 100%; 9 | height: 100vh; 10 | font-family: 'Montserrat', sans-serif; 11 | background: #eeeeee; 12 | color: #333333; 13 | transition: all 0.5s ease-in; 14 | } 15 | 16 | header { 17 | height: 25vh; 18 | } 19 | 20 | article { 21 | height: 60vh; 22 | } 23 | 24 | footer { 25 | height: 15vh; 26 | } 27 | 28 | 29 | header { 30 | display: flex; 31 | justify-content: space-between; 32 | align-items: center; 33 | } 34 | article, footer { 35 | display: grid; 36 | gap: 15px; 37 | justify-items: center; 38 | align-content: center; 39 | text-align: center; 40 | } 41 | 42 | body > * { 43 | padding: 0 15px; 44 | } 45 | 46 | a { 47 | text-decoration: none; 48 | font-size: 20px; 49 | color: #ffffff; 50 | padding: 10px 25px; 51 | background: teal; 52 | border-radius: 25px; 53 | transition: all 0.5s ease-in; 54 | } 55 | 56 | #toggle { 57 | cursor: pointer; 58 | font-size: 25px; 59 | width: 50px; 60 | height: 50px; 61 | border: 0; 62 | background: transparent; 63 | position: relative; 64 | } 65 | 66 | #toggle::before { 67 | content: '🔅'; 68 | } 69 | 70 | 71 | 72 | /** On Dark Mode 73 | **********************************/ 74 | 75 | .dark { 76 | color: #ffffff; 77 | background: #333333; 78 | } 79 | .dark a { 80 | background: #37d796; 81 | } 82 | 83 | .dark #toggle::before { 84 | content: '🔆'; 85 | } -------------------------------------------------------------------------------- /35-fluffyFrn/app.js: -------------------------------------------------------------------------------- 1 | const btns = document.querySelectorAll('.btn'); 2 | const cards = document.querySelectorAll('.card'); 3 | 4 | /* 5 | 1. Store the clicked button's %data text in a variable. 6 | 2. Loop through the cards/ boxes/ images. 7 | 3. Store the image's %data text into a variable. 8 | 4. If the button's %data text matches the image's %data text or the %data text 'all', show those images. Otherwise hide them. 9 | */ 10 | 11 | // Function ES6 12 | 13 | function filter () { 14 | cards.forEach(card => { 15 | [card.dataset.tag, 'all'].includes(this.dataset.tag) ? 16 | card.style.display = 'grid': 17 | card.style.display = 'none'; 18 | }); 19 | } 20 | 21 | 22 | // Event ES6 23 | btns.forEach(btn => btn.addEventListener('click', filter)); 24 | 25 | 26 | /* 27 | // FN ES5 28 | function filter () { 29 | const btnTag = this.dataset.tag; 30 | 31 | for (let i = 0; i < cards.length; i++) { 32 | cards[i]; 33 | const cardTag = cards[i].dataset.tag; 34 | 35 | if (btnTag == cardTag || btnTag == 'all') { 36 | cards[i].style.display = 'block'; 37 | } else { 38 | cards[i].style.display = 'none'; 39 | } 40 | } 41 | } 42 | 43 | // Event ES5 44 | for (let i = 0; i < btns.length; i++) { 45 | btns[i].addEventListener('click', filter); 46 | } 47 | */ -------------------------------------------------------------------------------- /35-fluffyFrn/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Fluffy Friends 8 | 9 | 14 | 15 | 16 | 17 |

    18 | Fluffy Friends 19 |

    20 | 21 | 27 | 28 |
    29 | dog 30 | cat 31 | dog 32 | rabbit 33 | cat 34 | dog 35 | rabbit 36 | dog 37 | cat 38 | dog 39 | rabbit 40 | cat 41 | 42 |
    43 | 44 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /35-fluffyFrn/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Kaushan+Script&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | html { 8 | font-size: 10px; 9 | } 10 | body { 11 | width: 100%; 12 | min-height: 100vh; 13 | font-size: 1.5rem; 14 | font-family: sans-serif; 15 | } 16 | 17 | h1 { 18 | text-align: center; 19 | font-size: 5rem; 20 | padding: 2rem 1rem; 21 | font-family: 'Kaushan Script', cursive; 22 | background-color: #f6d285; 23 | background-image: -webkit-linear-gradient(245deg, #bbf0f3 0%, #f6d285 74%); 24 | -webkit-background-clip: text; 25 | -webkit-text-fill-color: transparent; 26 | } 27 | 28 | nav { 29 | min-height: 10vh; 30 | padding: 2rem 1rem; 31 | display: flex; 32 | justify-content: center; 33 | align-items: center; 34 | flex-flow: row wrap; 35 | } 36 | .btn { 37 | min-width: 10rem; 38 | font-size: 1.75rem; 39 | font-weight: bold; 40 | color: #fff; 41 | margin: 1rem; 42 | padding: 0.75rem 1.25rem; 43 | border: 0; 44 | border-radius: 1rem; 45 | transition: all 0.5s ease; 46 | background: linear-gradient(315deg, #a40606 0%, #d98324 74%); 47 | clip-path: polygon(0% 15%, 15% 15%, 15% 0%, 85% 0%, 85% 15%, 100% 15%, 100% 85%, 85% 85%, 85% 100%, 15% 100%, 15% 85%, 0% 85%); 48 | } 49 | .btn:hover { 50 | transform: scale(1.1); 51 | } 52 | 53 | 54 | main { 55 | width: 100%; 56 | min-height: 80vh; 57 | padding: 2rem; 58 | display: grid; 59 | gap: 1.5rem; 60 | place-items: center; 61 | grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); 62 | } 63 | .card { 64 | max-width: 15rem; 65 | min-width: 15rem; 66 | height: 15rem; 67 | border: 0.5rem solid #d98324; 68 | clip-path: polygon(0 0, 95% 5%, 100% 100%, 0% 100%); 69 | transition: all 1s ease; 70 | object-fit: cover; 71 | position: relative; 72 | } 73 | .card:hover { 74 | clip-path: polygon(0 0, 100% 0%, 100% 100%, 0% 100%); 75 | } 76 | 77 | .footer { 78 | text-align: center; 79 | padding: 1rem; 80 | } 81 | .footer a { 82 | text-decoration: none; 83 | color: teal; 84 | } -------------------------------------------------------------------------------- /36-lineChart/app.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector('.form'); 2 | const charts = document.querySelector('.charts'); 3 | 4 | // HEX colors Random 5 | const randomHex = () => Math.random().toString(16).substr(-6); 6 | 7 | 8 | 9 | function createChart(e) { 10 | e.preventDefault(); 11 | 12 | // values 13 | const name = this.querySelector('.name').value; 14 | const value = this.querySelector('.val').value; 15 | const markup = 16 | `
    17 |
    18 | ${name} 19 | ${value} 20 |
    21 |
    ` 22 | 23 | // show in the UI 24 | charts.insertAdjacentHTML('beforeend', markup); 25 | } 26 | 27 | // Event 28 | form.addEventListener('submit', createChart); -------------------------------------------------------------------------------- /36-lineChart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Line Chart 8 | 9 | 10 | 11 |

    Line Chart

    12 | 13 |
    14 | 15 | 16 | 17 |
    18 | 19 |
    20 |
    21 |
    22 |
    23 | Carla 24 | 80 25 |
    26 |
    27 |
    28 |
    29 | 30 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /36-lineChart/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | html { 8 | font-size: 10px; 9 | font-family: 'Roboto', sans-serif; 10 | } 11 | body { 12 | width: 100%; 13 | min-height: 100vh; 14 | } 15 | 16 | h1 { 17 | text-align: center; 18 | color: #fff; 19 | background: #33415C; 20 | font-size: 3rem; 21 | height: 10vh; 22 | display: grid; 23 | place-items: center; 24 | } 25 | 26 | .form { 27 | background: #5C677D; 28 | min-height: 20vh; 29 | display: flex; 30 | flex-flow: row wrap; 31 | justify-content: center; 32 | align-items: center; 33 | } 34 | .form > * { 35 | height: 4rem; 36 | padding: 0.5rem 1rem; 37 | margin: 0.5rem; 38 | border: 1px solid #33415C; 39 | border-radius: 0.5rem; 40 | background: #fff; 41 | min-width: 15rem; 42 | font-family: inherit; 43 | } 44 | button { 45 | cursor: pointer; 46 | font-size: 2rem; 47 | font-weight: bold; 48 | color: #33415C; 49 | transition: transform 0.3s ease; 50 | } 51 | 52 | 53 | main { 54 | width: 100%; 55 | min-height: 70vh; 56 | display: grid; 57 | place-items: center; 58 | background: #DEE2E6; 59 | } 60 | .charts { 61 | border-bottom: 0.5rem solid #33415C; 62 | border-left: 0.5rem solid #33415C; 63 | min-width: 25%; 64 | height: 15rem; 65 | display: flex; 66 | align-items: flex-end; 67 | } 68 | .chart { 69 | width: 1rem; 70 | height: 80%; 71 | background: teal; 72 | margin: 0 0.25rem; 73 | transition: all 0.5s ease-out; 74 | position: relative; 75 | } 76 | .chart:hover { 77 | background: salmon; 78 | } 79 | 80 | .chart-snippet { 81 | display: none; 82 | } 83 | .chart:hover .chart-snippet { 84 | display: grid; 85 | place-items: center; 86 | min-width: 5rem; 87 | height: 3rem; 88 | background: rgba(0,0,0,0.7); 89 | color: #fff; 90 | position: absolute; 91 | top: -3rem; 92 | left: 0%; 93 | z-index: 999; 94 | transform: translate(-40%, calc(-100% + 1.5rem)); 95 | border-radius: 0.5rem; 96 | } 97 | .chart-snippet::after { 98 | content: ''; 99 | position: absolute; 100 | top: 100%; 101 | left: 30%; 102 | border-top: calc(2 * 1rem * 0.866) solid rgba(0,0,0,0.7); 103 | border-left: 1rem solid transparent; 104 | border-bottom: 1rem solid transparent; 105 | border-right: 1rem solid transparent; 106 | } 107 | 108 | .footer { 109 | background: #979DAC; 110 | padding: 1rem; 111 | text-align: center; 112 | } -------------------------------------------------------------------------------- /37-budgetApp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Budget App 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 |

    November 2020

    17 |

    $ 0.00

    18 |
    19 |

    Income

    20 |

    + 0.00

    21 |
    22 |
    23 |

    Expenses

    24 |

    - 0.00

    25 |

    26 | __% 27 |

    28 |
    29 |
    30 |
    31 | 32 |
    33 | 34 | 35 | 39 | 40 |
    41 | 42 |
    43 |
    44 |

    Income

    45 |
    46 |
    47 |

    48 | abc 49 |

    50 |

    51 | $ 0.00 52 |

    53 | 54 |
    55 |
    56 |
    57 | 58 |
    59 |

    Expense

    60 |
    61 |
    62 |

    63 | xyz 64 |

    65 |

    66 | $ 0.00 67 |

    68 | 69 |
    70 |
    71 |
    72 | 73 |
    74 | 75 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /38-duoToneCard/app.js: -------------------------------------------------------------------------------- 1 | const $ = s => document.querySelector(s); 2 | 3 | 4 | function gimme () { 5 | const hex1 = '#' + Math.random().toString(15).substr(-6); 6 | const hex2 = '#' + Math.random().toString(15).substr(-6); 7 | 8 | // colors 9 | $('.boxLeft').style.background = hex1; 10 | $('.boxLeft').style.color = hex2; 11 | $('.btnLeft').style.background = hex2; 12 | $('.btnLeft').style.color = hex1; 13 | 14 | $('.boxRight').style.background = hex2; 15 | $('.boxRight').style.color = hex1; 16 | $('.btnRight').style.background = hex1; 17 | $('.btnRight').style.color = hex2; 18 | 19 | // code snippets 20 | $('.left').textContent = hex1; 21 | $('.right').textContent = hex2; 22 | } 23 | 24 | gimme(); 25 | 26 | $('.btn').addEventListener('click', gimme); -------------------------------------------------------------------------------- /38-duoToneCard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Duo Tone Cards 8 | 9 | 10 | 11 | 12 |
    13 |
    14 |

    This is awesome

    15 |

    16 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi reprehenderit a quo possimus asperiores? Molestias suscipit libero aut eligendi et?. 17 |

    18 | 19 |
    20 | 21 |
    22 | 23 |

    24 | Top bg:
    25 | Bottom bg: 26 |

    27 |
    28 | 29 |
    30 |

    This is awesome too

    31 |

    32 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est fuga voluptate, animi ipsam consequatur recusandae rerum temporibus voluptatibus. Non, velit. 33 |

    34 | 35 |
    36 |
    37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /38-duoToneCard/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;600&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | html { 8 | font-size: 10px; 9 | font-family: 'Montserrat', sans-serif; 10 | } 11 | body { 12 | font-size: 1.8rem; 13 | color: #333333; 14 | } 15 | button { 16 | cursor: pointer; 17 | border: 0; 18 | border-radius: 2rem; 19 | padding: 1rem 2rem; 20 | } 21 | p { 22 | font-weight: 300; 23 | } 24 | 25 | main { 26 | width: 100%; 27 | min-height: 100vh; 28 | padding: 2rem 0; 29 | } 30 | section { 31 | width: 90%; 32 | max-width: 40rem; 33 | min-height: 10rem; 34 | margin: auto; 35 | padding: 1.5rem 2rem; 36 | border-radius: 1rem; 37 | } 38 | 39 | section h2 { 40 | font-size: 3rem; 41 | font-weight: 600; 42 | } 43 | .boxLeft p, 44 | .boxRight p { 45 | margin: 1.5rem 0; 46 | } 47 | .btnLeft, 48 | .btnRight { 49 | font-size: 1.8rem; 50 | } 51 | 52 | .codes { 53 | display: flex; 54 | justify-content: space-between; 55 | align-items: center; 56 | } 57 | .btn { 58 | background: #65e084; 59 | font-size: inherit; 60 | border-radius: 1.6rem 0px 1.6rem 0px; 61 | border-bottom: 0.3rem solid #DF8E00; 62 | } 63 | .codes p { 64 | border: 1px solid #65e084; 65 | border-radius: 1rem; 66 | font-size: 1.3rem; 67 | padding: 1rem; 68 | user-select: all; 69 | } 70 | 71 | .footer { 72 | text-align: center; 73 | padding: 1rem; 74 | font-size: 1.5rem; 75 | } -------------------------------------------------------------------------------- /39-contactApp/app.js: -------------------------------------------------------------------------------- 1 | //////////////////// Sort the contacts [put at the end] 2 | 3 | const contactList = document.querySelector('.contacts'); 4 | 5 | [...contactList.children] 6 | .sort((a, b) => 7 | a.dataset.name < b.dataset.name ? -1: 1) 8 | .forEach(node => contacts.appendChild(node)); -------------------------------------------------------------------------------- /39-contactApp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Contact App 9 | 10 | 11 | 12 |
    13 | 14 | 15 | 16 |
    17 | 34 |
    35 | 36 | 39 | 40 |
    41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
    50 | 51 |
    52 | 53 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /39-contactApp/readme.md: -------------------------------------------------------------------------------- 1 | # Contact App 2 | 3 | [Live link](https://all-js.netlify.app/39-contactApp) 4 | 5 | ## Features 6 | 7 | - Add contact in localStorage 8 | - Sort by names (Capital letter only) 9 | - Remove contact 10 | - Search contact 11 | - If there's no image, the names initials will be there 12 | - Random Hexadecimal colors for image's border or fallback's background 13 | 14 | 15 | ## Improvements that can be done 16 | 17 | - Form validation 18 | - Input for image 19 | - Multiple emails 20 | - More fields for cities, countries etc 21 | - Popup or modal on click on selected contact 22 | - Batch delete 23 | - If the number is there, new contact can't be added -------------------------------------------------------------------------------- /40-weatherClock/api.js: -------------------------------------------------------------------------------- 1 | const input = document.querySelector('.search'); 2 | 3 | // API 4 | const key = 'mvi50abeoSc85sh0lVJWN14MGbmj50vs'; 5 | 6 | // async 7 | 8 | // https://dataservice.accuweather.com/currentconditions/v1/26216?apikey=mvi50abeoSc85sh0lVJWN14MGbmj50vs 9 | 10 | // a. for current condition of weahter 11 | async function getWeather (id) { 12 | const base = 'https://cors-anywhere.herokuapp.com/https://dataservice.accuweather.com/currentconditions/v1/'; 13 | const query = `${id}?apikey=${key}`; 14 | 15 | try { 16 | const res = await fetch(base + query); 17 | const data = await res.json(); 18 | input.style.borderColor = 'rgba(18, 103, 130, 0.75)'; 19 | 20 | return { 21 | cityTime: data[0].LocalObservationDateTime.slice(11, 22 | 16), 23 | cityIsDay: data[0].IsDayTime, 24 | cityTemp: data[0].Temperature.Metric.Value, 25 | cityTempText: data[0].WeatherText, 26 | }; 27 | } 28 | catch(err) { 29 | console.log(err); 30 | input.style.borderColor = 'salmon'; 31 | } 32 | 33 | } 34 | 35 | //https://dataservice.accuweather.com/locations/v1/cities/search?apikey=mvi50abeoSc85sh0lVJWN14MGbmj50vs&q=Dhaka 36 | // b. for the cities 37 | async function getCity (city) { 38 | const base = 'https://cors-anywhere.herokuapp.com/https://dataservice.accuweather.com/locations/v1/cities/search'; 39 | const query = `?apikey=${key}&q=${city}`; 40 | try { 41 | const res = await fetch(base + query); 42 | const data = await res.json(); 43 | input.style.borderColor = 'rgba(18, 103, 130, 0.75)'; 44 | 45 | return { 46 | cityKey: data[0].Key, 47 | cityName: data[0].EnglishName, 48 | country: data[0].Country.ID, 49 | }; 50 | } 51 | catch (err) { 52 | console.log(err); 53 | input.style.borderColor = 'salmon'; 54 | } 55 | } 56 | 57 | 58 | function displayCity(container, arr = []) { 59 | container.innerHTML = arr.map((x, i) => { 60 | return `
    61 |
    62 |

    ${x.cityName}

    63 |

    ${x.cityTime}

    64 |

    ${x.cityTemp}°C

    65 |
    66 | 67 |
    `; 68 | }) 69 | .join(''); 70 | } -------------------------------------------------------------------------------- /40-weatherClock/app.js: -------------------------------------------------------------------------------- 1 | // Elements 2 | const $ = x => document.querySelector(x); 3 | const cityList = $('#cityList'); 4 | 5 | let cities = JSON.parse(localStorage.getItem('cities')) || []; 6 | 7 | // Delete City 8 | function deleteCity(e) { 9 | const [el, 10 | id] = [e.target, 11 | e.target.dataset.id]; 12 | 13 | if (el.classList.contains('delete')) { 14 | cities.splice(id, 1); 15 | 16 | // Display on UI 17 | displayCity(cityList, cities); 18 | localStorage.setItem('cities', JSON.stringify(cities)); 19 | } 20 | } 21 | 22 | // main function 23 | async function showTime(e) { 24 | e.preventDefault(); 25 | 26 | const value = this.querySelector('input').value.trim(); 27 | 28 | // values from City 29 | const m = await getCity(value); 30 | const cityKey = m.cityKey; 31 | const cityName = m.cityName; 32 | const country = m.country; 33 | 34 | // Values from Weather ; 35 | const w = await getWeather(cityKey); 36 | const cityTime = w.cityTime; 37 | const cityIsDay = w.cityIsDay; 38 | const cityTemp = Math.round(w.cityTemp); 39 | const cityTempText = w.cityTempText; 40 | 41 | // Create an Object 42 | const obj = { 43 | cityKey, 44 | cityName, 45 | country, 46 | cityTime, 47 | cityIsDay, 48 | cityTemp, 49 | cityTempText 50 | }; 51 | 52 | // Push the Object in the Arr 53 | cities.push(obj); 54 | 55 | // Display on UI 56 | displayCity(cityList, cities); 57 | 58 | // Add on localStorage 59 | localStorage.setItem('cities', JSON.stringify(cities)); 60 | 61 | // Reset the form 62 | this.reset(); 63 | } 64 | 65 | 66 | 67 | 68 | // event 69 | $('.form').addEventListener('submit', showTime); 70 | cityList.addEventListener('click', deleteCity); 71 | 72 | 73 | // on load 74 | displayCity(cityList, cities); -------------------------------------------------------------------------------- /40-weatherClock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | World Weather Clock 9 | 14 | 15 | 16 | 17 |
    18 |

    Weather & Clock

    19 |
    20 | 21 |
    22 |
    23 |
    24 |
    25 | 26 |
    27 |
    28 |
    29 |
    30 | 46 |
    47 |
    48 |
    49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /40-weatherClock/readme.md: -------------------------------------------------------------------------------- 1 | # World Weather & Clock 2 | 3 | [Live Link](https://all-js.netlify.app/40-weatherClock) 4 | 5 | ## Credit 6 | 7 | API is provided by [Accu Weather](https://developer.accuweather.com) -------------------------------------------------------------------------------- /40-weatherClock/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap'); 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | } 7 | html { 8 | font-size: 10px; 9 | font-family: 'Open Sans', sans-serif; 10 | } 11 | body { 12 | font-size: 1.5rem; 13 | line-height: 1.6; 14 | color: #333333; 15 | width: 100%; 16 | } 17 | 18 | .centered { 19 | display: grid; 20 | place-items: center; 21 | } 22 | 23 | header { 24 | width: 100%; 25 | min-height: 15vh; 26 | padding: 1rem; 27 | font-size: 2.25rem; 28 | font-weight: 600; 29 | text-align: center; 30 | color: #fff; 31 | background: rgba(33, 158, 188, 1); 32 | } 33 | 34 | main { 35 | width: 100%; 36 | min-height: 85vh; 37 | background: rgba(88, 180, 209, 1); 38 | } 39 | 40 | .cards { 41 | width: 90%; 42 | min-height: 10rem; 43 | background: #8ECAE6; 44 | margin: 1rem 0; 45 | display: grid; 46 | gap: 1rem; 47 | grid-template-columns: repeat(auto-fit, minmax(30rem, 1fr)); 48 | /* align-content: center;justify-content: center; */ 49 | border-radius: 1rem; 50 | box-shadow: inset -20px -20px 60px #2a86b0, 51 | inset 20px 20px 60px #3ab8f2; 52 | } 53 | .card { 54 | min-height: 20rem; 55 | padding: 1rem; 56 | display: flex; 57 | flex-direction: column; 58 | } 59 | .cardLeft { 60 | background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/World_map_%28blue_dots%29.svg/1200px-World_map_%28blue_dots%29.svg.png); 61 | background-size: cover; 62 | background-position: center center; 63 | } 64 | .form { 65 | height: 4rem; 66 | display: grid; 67 | place-items: center; 68 | } 69 | .form input { 70 | height: 100%; 71 | width: 25rem; 72 | padding: 0.5rem 1rem; 73 | border: 2px solid rgba(18, 103, 130, 0.75); 74 | border-radius: 0.75rem; 75 | background: rgba(255,255,255,0.5); 76 | font-size: 2rem; 77 | } 78 | 79 | .cardRight { 80 | justify-content: center; 81 | align-items: center; 82 | } 83 | .city { 84 | width: 80%; 85 | height: 5rem; 86 | margin: 0.5rem 0 0.5rem 1rem; 87 | font-size: 2rem; 88 | font-weight: 400; 89 | position: relative; 90 | } 91 | .city .container { 92 | position: absolute; 93 | top: 0; 94 | left: 0; 95 | width: 100%; 96 | height: 100%; 97 | display: flex; 98 | justify-content: space-between; 99 | align-items: center; 100 | z-index: 1; 101 | border-radius: 0.75rem; 102 | padding: 0.5rem 1rem; 103 | } 104 | .delete { 105 | position: absolute; 106 | top: 0rem; 107 | right: -0.5rem; 108 | width: 4rem; 109 | height: 100%; 110 | padding-left: 1rem; 111 | background: salmon; 112 | color: #fff; 113 | font-size: 2rem; 114 | border: 0; 115 | outline: 0; 116 | border-radius: 0.75rem; 117 | display: grid; 118 | place-items: center; 119 | z-index: 0; 120 | transition: all 0.5s ease; 121 | } 122 | .city:hover .delete { 123 | right: -3rem; 124 | } 125 | 126 | .container.day { 127 | background: #fff; 128 | color: #333; 129 | } 130 | .container.night { 131 | background: #333; 132 | color: #fff; 133 | } 134 | 135 | 136 | 137 | footer { 138 | text-align: center; 139 | font-size: 1.3rem; 140 | padding: 1rem; 141 | color: #ddd; 142 | background: rgba(18, 103, 130, 1); 143 | } 144 | 145 | footer a { 146 | text-decoration: none; 147 | color: #bee; 148 | } -------------------------------------------------------------------------------- /41-lazyLoading/app.js: -------------------------------------------------------------------------------- 1 | const $ = x => document.querySelector(x); 2 | const section1 = $('#section1'); 3 | const nav = $('.nav'); 4 | const goTop = $('#top'); 5 | 6 | // Height of the nav 7 | const navHeight = nav.getBoundingClientRect().bottom + 'px'; 8 | 9 | // Callback 10 | const stickyNav = function(entries) { 11 | 12 | // if isIntersecting isn't true, show sticky or hide 13 | // entries[0] meaning the first value from the threshold 14 | if (!entries[0].isIntersecting) { 15 | nav.classList.add('sticky'); 16 | goTop.style.transform = 'scale(1)'; 17 | } else { 18 | nav.classList.remove('sticky'); 19 | goTop.style.transform = 'scale(0)'; 20 | } 21 | }; 22 | 23 | // a callback & some options 24 | const observeSection1 = new IntersectionObserver(stickyNav, { 25 | root: null, 26 | threshold: 0, 27 | rootMargin: `-${navHeight}` //based on getBounding Client 28 | }); 29 | 30 | 31 | // observe the element 32 | observeSection1.observe(section1); 33 | 34 | 35 | 36 | //////////////////////// Reveal 37 | // All sections 38 | const contents = document.querySelectorAll('.content'); 39 | 40 | // The Callback 41 | const revealSection = (entries, observer) => { 42 | const [entry] = entries; 43 | 44 | // IF the entry is not intersecting, return nothing 45 | if (!entry.isIntersecting) return; 46 | entry.target.classList.remove('hidden'); 47 | 48 | // IF it's done once, stop observing & slow my app 49 | observer.unobserve(entry.target); 50 | }; 51 | 52 | // The Observer 53 | const observeContent = new IntersectionObserver(revealSection, { 54 | root: null, 55 | threshold: 0.25 56 | }); 57 | 58 | // Setting Observe 59 | contents.forEach(content => { 60 | observeContent.observe(content); 61 | content.classList.add('hidden'); 62 | }); 63 | 64 | 65 | /////////////////////// Lazy Load Image 66 | // All the lazy images 67 | const imgs = document.querySelectorAll('img[data-src]'); 68 | 69 | 70 | // The Callback 71 | const lazyToActive = (entries, observer) => { 72 | const [entry] = entries; 73 | 74 | // IF the image is not being intersecting, return nothing 75 | if (!entry.isIntersecting) return; 76 | 77 | // change src 78 | entry.target.src = entry.target.dataset.src; 79 | 80 | // remove the blur on load 81 | entry.target.addEventListener('load', 82 | ()=> entry.target.classList.remove('lazy')); 83 | }; 84 | 85 | // New API 86 | const lazyImg = new IntersectionObserver(lazyToActive, { 87 | root: null, 88 | threshold: 0.15 89 | }); 90 | 91 | 92 | // Observing 93 | imgs.forEach(img => lazyImg.observe(img)); -------------------------------------------------------------------------------- /41-lazyLoading/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Sticky Nav ft. Intersecting Observer 9 | 14 | 15 | 16 | 🎈 17 | 18 |
    19 | 25 |
    26 |

    27 | Lazy Loading... 28 |

    29 |
    30 |
    31 |
    32 | 38 |
    39 |
    40 |
    41 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cumque quas, doloribus ex, nemo eaque aliquid nostrum natus soluta blanditiis molestias expedita ipsum ea in dolorem ad praesentium dolores libero vel. 42 |
    43 |
    44 |
    45 |
    46 | Made by Tutul 47 |
    48 | See my other JS projects 49 |
    50 |
    51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /41-lazyLoading/placeholder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TutulDevs/All-JavaScript/08cfc69022af640155a23c5d678aa584f0061e68/41-lazyLoading/placeholder.jpeg -------------------------------------------------------------------------------- /41-lazyLoading/readme.md: -------------------------------------------------------------------------------- 1 | # Sticky Nav with Intersection Observation API 2 | 3 | [Live Link](https://all-js.netlify.app/41-stickyNav) -------------------------------------------------------------------------------- /41-lazyLoading/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | html { 9 | scroll-behavior: smooth; 10 | } 11 | 12 | .centered { 13 | display: grid; 14 | place-items: center; 15 | text-align: center; 16 | } 17 | 18 | section { 19 | width: 100%; 20 | min-height: 100vh; 21 | color: #fff; 22 | font-family: sans-serif; 23 | } 24 | #section1 { 25 | background: #84A98C; 26 | } 27 | #section2 { 28 | background: #52796F; 29 | } 30 | #section3 { 31 | background: #354F52; 32 | } 33 | #section4 { 34 | background: #3D5A80; 35 | } 36 | .content { 37 | padding: 1em; 38 | transform: translate(0rem); 39 | transition: all 1s ease; 40 | } 41 | .title { 42 | height: 80vh; 43 | display: flex; 44 | justify-content: center; 45 | align-items: center; 46 | } 47 | h1 { 48 | text-align: center; 49 | font-size: 3em; 50 | font-family: 'Major Mono Display', monospace; 51 | } 52 | 53 | .hidden { 54 | opacity: 0; 55 | transform: translate(-5rem, 5rem); 56 | } 57 | 58 | 59 | #section1 .content { 60 | height: 80vh; 61 | } 62 | 63 | .link { 64 | text-decoration: none; 65 | font-size: 1.15em; 66 | color: #fff; 67 | background: #52796F; 68 | padding: 0.15em 0.5em; 69 | margin: 0.25em; 70 | border-radius: 0.75em; 71 | transition: all 0.3s ease-in-out; 72 | box-shadow: 0 0 0 0 rgba(0,0,0,0.0); 73 | } 74 | .link:hover { 75 | box-shadow: 0 0 0.75em -0.25em #52796F; 76 | } 77 | 78 | .nav { 79 | background: #2F3E46; 80 | color: #fff; 81 | text-align: center; 82 | height: 20vh; 83 | display: flex; 84 | flex-flow: row wrap; 85 | justify-content: center; 86 | align-items: center; 87 | font-family: 'Major Mono Display', monospace; 88 | z-index: 999; 89 | } 90 | 91 | .nav.sticky { 92 | position: fixed; 93 | top: 0; 94 | width: 100%; 95 | background: rgba(255,255,255,0.8); 96 | color: #333; 97 | transform: rotateZ(5deg) rotateX(65deg) scaleY(1.2); 98 | transform-origin: 50%; 99 | box-shadow: 0 5px 15px -5px rgba(0,0,0,0.5); 100 | animation: ease-in-out forwards; 101 | animation-name: animateSticky; 102 | animation-duration: 1s; 103 | } 104 | 105 | #top { 106 | text-decoration: none; 107 | position: fixed; 108 | bottom: 0.5em; 109 | right: 0.5em; 110 | font-size: 1.5em; 111 | width: 1.75em; 112 | height: 1.75em; 113 | border: 1px solid #E76F51; 114 | border-radius: 50%; 115 | transition: all 0.5s ease-in; 116 | transform: scale(0); 117 | } 118 | 119 | 120 | 121 | .gallery { 122 | margin-top: 20vh; 123 | margin-bottom: 2em; 124 | display: flex; 125 | flex-flow: row wrap; 126 | justify-content: center; 127 | align-items: center; 128 | } 129 | .img { 130 | width: 300px; 131 | height: 225px; 132 | margin: 0.5em; 133 | box-shadow: 0 5px 15px -5px rgba(255,255,25,0.7); 134 | } 135 | .lazy { 136 | filter: blur(2px); 137 | } 138 | 139 | 140 | 141 | @keyframes animateSticky { 142 | 0% { 143 | transform: rotateZ(5deg) rotateX(65deg) scaleY(1.2); 144 | } 145 | 70% { 146 | transform: rotateZ(0deg) rotateX(0deg) scaleY(1); 147 | } 148 | 90% { 149 | transform: rotateZ(0deg) rotateX(0deg) scaleY(0.7); 150 | } 151 | 100% { 152 | transform: rotateZ(0deg) rotateX(0deg) scaleY(1); 153 | } 154 | } -------------------------------------------------------------------------------- /42-JSBank/app.js: -------------------------------------------------------------------------------- 1 | const $ = x => document.querySelector(x); 2 | const homepage = $('.homepage'); 3 | const banking = $('.banking'); 4 | const infoBox = $('.infoBox'); 5 | let sumTotal = 1250; 6 | 7 | 8 | const date = `${new Date().getDate()}/${new Date().getMonth() + 1}/'${String(new Date().getFullYear()).slice(2, 4)}`; // date/month/'year 9 | 10 | 11 | // Deposit functions 12 | function depositMoney(e) { 13 | e.preventDefault(); 14 | 15 | const value = Number(this.querySelector('input').value); 16 | $('.sum').textContent = (sumTotal += value); 17 | const markup = `
  • 18 |

    Deposit

    19 |

    ${date}

    20 |

    ${value} €

    21 |
  • `; 22 | infoBox.insertAdjacentHTML('afterbegin', markup); 23 | this.reset(); 24 | } 25 | 26 | $('.depForm').addEventListener('submit', depositMoney); 27 | 28 | 29 | // withdraw functions 30 | function withdrawMoney(e) { 31 | e.preventDefault(); 32 | 33 | const value = Number(this.querySelector('input').value); 34 | $('.sum').textContent = (sumTotal -= value); 35 | const markup = ` 36 |
  • 37 |

    Withdrawn

    38 |

    ${date}

    39 |

    -${value} €

    40 |
  • `; 41 | infoBox.insertAdjacentHTML('afterbegin', markup); 42 | this.reset(); 43 | } 44 | 45 | $('.witForm').addEventListener('submit', withdrawMoney); 46 | 47 | 48 | 49 | 50 | // Login functions a@b.dev 51 | function login (e) { 52 | e.preventDefault(); 53 | const email = this.querySelector('.email').value; 54 | const password = this.querySelector('.password').value; 55 | 56 | // IF email & pass matches, hide the home page, show the banking 57 | if (email === 'a@b.dev' && password === '1234') { 58 | console.log(email, password); 59 | homepage.style.display = 'none'; 60 | banking.style.display = 'block'; 61 | 62 | this.innerHTML = `

    John Doe

    `; 63 | } 64 | 65 | } 66 | $('.loginForm').addEventListener('submit', login); -------------------------------------------------------------------------------- /42-JSBank/readme.md: -------------------------------------------------------------------------------- 1 | # JS Bank 2 | 3 | A simple banking simulation app. 4 | 5 | [Live link](https://all-js.netlify.app/42-JSBank) -------------------------------------------------------------------------------- /43-Furnit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Furnit 10 | 11 | 12 | 13 |
    14 | 15 | 18 |
    19 | 20 |
    21 |

    The Place Where Class Meets Quality

    22 | Shop Now 23 |
    24 | 25 |
    26 |

    Featured Products

    27 | 28 |
    29 | 38 |
    39 | 40 | 43 |
    44 | 45 | 49 | 50 |
    51 |
    52 |
    53 |

    Your Cart

    54 | 55 |
    56 | 57 |
    58 | 75 |
    76 | 77 | 81 |
    82 |
    83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /43-Furnit/products.js: -------------------------------------------------------------------------------- 1 | const products = [{ 2 | id: 1, 3 | name: 'queen panel bed', 4 | price: 124.99, 5 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-1.jpeg' 6 | }, { 7 | id: 2, 8 | name: 'king panel bed', 9 | price: 119.25, 10 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-2.jpeg' 11 | }, { 12 | id: 3, 13 | name: 'single panel bed', 14 | price: 79.49, 15 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-3.jpeg' 16 | }, { 17 | id: 4, 18 | name: 'twin panel bed', 19 | price: 99, 20 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-4.jpeg' 21 | }, { 22 | id: 5, 23 | name: 'Fridge', 24 | price: 88.99, 25 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-5.jpeg' 26 | }, { 27 | id: 6, 28 | name: 'dresser', 29 | price: 48.75, 30 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-6.jpeg' 31 | }, { 32 | id: 7, 33 | name: 'couch', 34 | price: 25.88, 35 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-7.jpeg' 36 | }, { 37 | id: 8, 38 | name: 'Table', 39 | price: 10.55, 40 | img: 'https://raw.githubusercontent.com/john-smilga/setup-files-js-comfy-house/master/images/product-8.jpeg' 41 | }]; -------------------------------------------------------------------------------- /43-Furnit/readme.md: -------------------------------------------------------------------------------- 1 | # Furnit 2 | 3 | A simple e-commerce site made with the help of John Smilga's [tutorial](https://m.youtube.com/watch?v=90PgFUPIybY) -------------------------------------------------------------------------------- /43-Furnit/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | html { 9 | font-size: 10px; 10 | } 11 | body { 12 | font-family: 'Montserrat', sans-serif !important; 13 | width: 100%; 14 | min-height: 100vh; 15 | font-size: 1.5rem; 16 | } 17 | 18 | .card-title , .cart-item-name { 19 | text-transform: capitalize; 20 | } 21 | 22 | button:disabled { 23 | background: gray; 24 | } 25 | 26 | header { 27 | width: 100%; 28 | height: 20vh; 29 | padding: 0 2.5%; 30 | display: flex; 31 | justify-content: space-between; 32 | align-items: center; 33 | } 34 | 35 | .cart-btn { 36 | background: transparent; 37 | border: 0; 38 | font-size: 2.25rem; 39 | color: #fff; 40 | padding: 5px 10px; 41 | border-radius: 25px; 42 | } 43 | .cart-btn .total-quantity { 44 | background: tomato; 45 | font-size: 1.25rem; 46 | display: inline-block; 47 | padding: 2px 8px; 48 | border-radius: 0.5rem; 49 | transform: translate(70%, -80%); 50 | } 51 | 52 | .home { 53 | height: 80vh; 54 | text-align: center; 55 | display: grid; 56 | justify-items: center; 57 | align-content: center; 58 | gap: 1rem; 59 | background-color: #f9c1b1; 60 | background-image: url('https://cdn.pixabay.com/photo/2014/09/15/21/46/couch-447484_1280.jpg'); 61 | background-size: cover; 62 | background-attachment: fixed; 63 | position: relative; 64 | z-index: 2; 65 | } 66 | .home::before { 67 | content: ''; 68 | position: absolute; 69 | width: 100%; 70 | height: 100%; 71 | background: rgba(255,255,255,0.2); 72 | z-index: 1; 73 | } 74 | .home .btn { 75 | padding: 1rem 2rem; 76 | font-size: 2rem; 77 | } 78 | 79 | 80 | .main { 81 | min-height: 100vh; 82 | padding: 0 2.5%; 83 | } 84 | .main-title, .main-footer { 85 | min-height: 15vh; 86 | display: grid; 87 | place-items: center; 88 | } 89 | .items { 90 | min-height: 80vh; 91 | display: grid; 92 | gap: 1rem; 93 | grid-template-columns: repeat(auto-fit, minmax(30rem, 1fr)); 94 | place-items: center; 95 | } 96 | .card-img-top { 97 | width: 30rem; 98 | height: 20rem; 99 | object-fit: cover; 100 | } 101 | .toCart { 102 | font-weight: bold; 103 | font-size: 1.6rem; 104 | } 105 | 106 | .main-footer a { 107 | font-size: 1.75rem; 108 | width: 20rem; 109 | } 110 | 111 | 112 | .cart-overlay { 113 | position: fixed; 114 | top: 0; 115 | left: 0; 116 | width: 100%; 117 | height: 100vh; 118 | background: rgba(0,0,0,0.6); 119 | transition: transform 0.5s ease-in-out; 120 | transform: translateX(100%); 121 | z-index: 999; 122 | } 123 | 124 | .show-cart .cart-overlay { 125 | transform: translateX(0); 126 | } 127 | 128 | .cart { 129 | width: 100%; 130 | max-width: 40rem; 131 | height: 100vh; 132 | position: absolute; 133 | top: 0; 134 | right: 0; 135 | overflow-y: scroll; 136 | } 137 | .cart-header { 138 | display: flex; 139 | justify-content: space-between; 140 | } 141 | 142 | .cart-content { 143 | min-height: 60vh; 144 | } 145 | .cart-item { 146 | display: flex; 147 | justify-content: space-between; 148 | align-items: center; 149 | } 150 | .cart-desc { 151 | display: flex; 152 | } 153 | .cart-desc-img { 154 | width: 10rem; 155 | height: 8.5rem; 156 | object-fit: cover; 157 | } 158 | 159 | .tools .btn { 160 | font-size: 1.7rem; 161 | } 162 | .cart-item-quantity { 163 | border: 0; 164 | } -------------------------------------------------------------------------------- /44-pagination/app.js: -------------------------------------------------------------------------------- 1 | // Async 2 | const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; 3 | async function getInfo() { 4 | try { 5 | const res = await fetch(endpoint); 6 | let data = await res.json(); 7 | data = await data.splice(0, 100); 8 | return data; 9 | } catch (err) { 10 | console.log(err); 11 | } 12 | } 13 | 14 | // Display table 15 | function tableData(container, arr) { 16 | container.innerHTML = arr.map((el, i) => { 17 | return ` 18 | ${arr[i].rank} 19 | ${arr[i].city} 20 | ${arr[i].state} 21 | ${arr[i].population} 22 | `; 23 | }).join(''); 24 | } 25 | 26 | // ELements 27 | const $ = x => document.querySelector(x); 28 | const select = $('.select'); 29 | const tbody = $('.tbody'); 30 | const pagiList = $('.pagination'); 31 | 32 | const numFormat = new Intl.NumberFormat('en-US'); 33 | let itemsArr = []; 34 | let perPage = 10; 35 | 36 | async function showTime() { 37 | let m = await getInfo(); 38 | 39 | for (let i = 0; i < m.length; i++) { 40 | let obj = { 41 | rank: m[i].rank, 42 | city: m[i].city, 43 | state: m[i].state, 44 | population: numFormat.format(m[i].population) 45 | }; 46 | itemsArr.push(obj); 47 | } 48 | 49 | let totalPages = Math.ceil(m.length / perPage); 50 | 51 | // show btns 52 | for (let i = 0; i < totalPages; i++) { 53 | let markup = `
  • ${i+1}
  • `; 54 | pagiList.insertAdjacentHTML('beforeend', markup); 55 | } 56 | 57 | // for displaying at first 58 | function paginate(arr, perPage, pageNumber = 1) { 59 | perPage = perPage; 60 | const start = perPage * (pageNumber - 1); 61 | let nr = arr.slice(start, (start + perPage)); 62 | tableData(tbody, nr); 63 | } 64 | paginate(itemsArr, perPage); 65 | 66 | const btns = [...document.querySelectorAll('.pagi-btn')]; 67 | btns[0].style.background = '#48CAE4'; 68 | 69 | btns.forEach(el => el.addEventListener('click', function() { 70 | btns.forEach(el => el.style.background = 'transparent'); 71 | this.style.background = '#48CAE4'; 72 | 73 | pageNumber = Number(this.dataset.id); 74 | paginate(itemsArr, perPage, pageNumber); 75 | })); 76 | 77 | } 78 | 79 | 80 | 81 | // load on first 82 | showTime(); 83 | 84 | 85 | 86 | 87 | //////// Pagination Fnction 88 | /* 89 | 90 | select.addEventListener('change', function(){ 91 | perPage = Number(this.value) ; 92 | }); 93 | 94 | let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']; 95 | function paginateArray(ary, perPage = 10, pageNumber = 1) { 96 | const start = perPage * (pageNumber - 1); 97 | return ary.slice(start, (start + perPage)); 98 | } 99 | */ -------------------------------------------------------------------------------- /44-pagination/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Pagination 10 | 11 | 12 | 13 |
    14 |

    15 | 100 Top US Cities by Population 16 |

    17 |
    18 |
    19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 35 | 36 |
    #CityStatePopulation
    37 | 38 | 41 |
    42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /44-pagination/readme.md: -------------------------------------------------------------------------------- 1 | # Pagination practice 2 | 3 | [Live Link](https://all-js.netlify.app/44-pagination) -------------------------------------------------------------------------------- /44-pagination/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10px; 3 | } 4 | body { 5 | font-size: 1.6rem; 6 | } 7 | header { 8 | width: 100%; 9 | min-height: 15vh; 10 | display: grid; 11 | place-items: center; 12 | } 13 | main { 14 | width: 100%; 15 | min-height: 85vh; 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: space-evenly; 19 | background-image: repeating-linear-gradient(45deg, rgb(255,255,255) 0px, rgb(255,255,255) 10px,transparent 10px, transparent 11px),repeating-linear-gradient(135deg, rgb(255,255,255) 0px, rgb(255,255,255) 10px,transparent 10px, transparent 11px),linear-gradient(90deg, hsl(256,7%,84%),hsl(256,7%,84%)); 20 | } 21 | .table { 22 | width: 98%; 23 | max-width: 60rem; 24 | margin: 2rem auto; 25 | } 26 | .tbody tr:nth-child(odd) { 27 | background: #48CAE4; 28 | } 29 | .tbody tr:nth-child(even) { 30 | background: #ADE8F4; 31 | } 32 | .pagination { 33 | display: flex; 34 | flex-flow: row wrap; 35 | } -------------------------------------------------------------------------------- /Console/03 FizzBuzz.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FizzBuzz 7 | 10 | 11 | 12 | 13 |
    14 |         
    15 |         let answer = parseInt(prompt("Please enter the number"));
    16 | 
    17 |         console.log("Welcome in FizzBuzz Game")
    18 |         console.log( "Your input is " + answer );
    19 | 
    20 |         for (let i = 1; i <= answer; i++) {
    21 |             if(i % 3 === 0 && i% 5=== 0) {
    22 |                 console.log("FizzBuzz");
    23 |             } else if (i % 3 === 0) {
    24 |                 console.log("Fizz");
    25 |             } else if (i % 5 ===0) {
    26 |                 console.log("Buzz");
    27 |             } else {
    28 |                 console.log(i);
    29 |             }
    30 |         }
    31 |     
    32 | 33 | 34 | 52 | 53 | -------------------------------------------------------------------------------- /Console/arrayCardio-02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Array Cardio 02 💪💪 6 | 7 | 8 |

    Array Cardio 02 💪💪

    9 |

    Psst: have a look at the JavaScript Console 💁

    10 | 11 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Console/devTool.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Console Tricks! 6 | 7 | 8 |

    ×BREAK×DOWN×

    9 | 10 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # All Vanilla JavaScript Projects 2 | 3 | 4 | This repo is the collection of all my vanilla JavaScript projects. But I've some more, which are not in this repo. Go to the live link to see them all. 5 | 6 | 7 | 👉 [The site](https://all-js.netlify.app/) for the live links. 8 | 9 | ## Credits 10 | 11 | - to be added -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | All JS 10 | 11 | 12 |
    13 |

    All JS Projects

    14 |

    15 | JavaScript felt hard & I became stubborn. This list is the result of those events. 16 |

    17 |

    18 | I hope this list will help JavaScript newbies & those who are looking 19 | for project ideas. 20 |

    21 |

    22 | Contact: 23 | Twitter 24 | GitHub 25 | Codepen 26 | CodeWars 27 | Hashnode 28 |

    29 |
    30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 59 | 60 |
    LiveCodeNotes
    61 | 62 | 63 | 64 | 65 | 66 | --------------------------------------------------------------------------------