├── .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 | Generate
19 |
20 |
21 |
22 |
23 |
24 |
Random Hexadecimal Color Generator
25 | Hex Code
26 | Generate
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 |
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 |
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 |
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 |
14 |
1
15 |
16 |
17 |
18 |
2
19 |
20 |
21 |
22 |
3
23 |
24 |
25 |
26 |
27 |
32 |
Jane Doe
33 |
4
34 |
35 |
36 |
37 |
38 |
39 | prev
40 |
41 | next
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 | ${plate.text}
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 |
23 | No list to show
24 |
36 |
37 |
58 |
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 |
23 | Name ▲
24 |
25 |
26 | Age ▲
27 |
28 |
29 | Birthday ▲
30 |
31 |
32 |
33 |
34 |
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 |
14 |
21 |
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 |
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 | Weight:
14 |
15 |
16 |
17 |
18 | Height:
19 |
20 |
21 |
22 |
Your BMI is: 00
23 |
24 |
25 | BMI
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 |
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 |
27 |
28 |
Michelle Appleton
29 |
28 July 2020
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
Share
41 |
42 |
43 |
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 |
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 |
123 |
124 |
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 |
17 |
18 |
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 |
22 | All
23 | Dog
24 | Cat
25 | Rabbit
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
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 | Create
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 |
31 |
32 |
33 |
34 |
35 |
36 | +
37 | -
38 |
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 | Button
19 |
20 |
21 |
22 | Gimme
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 | Button
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 |
35 |
36 |
37 | +
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Add Contact
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 |
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 |
31 |
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 |
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 | Furnit
15 |
16 | 0 🛒
17 |
18 |
19 |
20 |
21 |
The Place Where Class Meets Quality
22 |
Shop Now
23 |
24 |
25 |
26 | Featured Products
27 |
28 |
39 |
40 |
43 |
44 |
45 |
46 | Made by Tutul . Inspired by John Smilga .
47 | See my other JS Projects .
48 |
49 |
50 |
51 |
52 |
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 | City
24 | State
25 | Population
26 |
27 |
28 |
29 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 | Made by Tutul .
45 | See my other JS projects .
46 |
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 | Live
36 | Code
37 | Notes
38 |
39 |
40 |
41 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------