├── .gitignore ├── 01 - JavaScript Drum Kit ├── background.jpg ├── index.html ├── readme.md ├── sounds │ ├── boom.wav │ ├── clap.wav │ ├── hihat.wav │ ├── kick.wav │ ├── openhat.wav │ ├── ride.wav │ ├── snare.wav │ ├── tink.wav │ └── tom.wav └── style.css ├── 02 - JS + CSS Clock ├── DeathtoStock_QuietFrontier-11.jpg ├── index.html └── readme.md ├── 03 - CSS Variables ├── Death_to_stock_BMX1_10.jpg ├── index.html └── readme.md ├── 04 - Array Cardio Day 1 ├── index.html └── readme.md ├── 05 - Flex Panel Gallery ├── index.html └── readme.md ├── 06 - Type Ahead ├── index.html ├── readme.md └── style.css ├── 07 - Array Cardio Day 2 ├── index.html └── readme.md ├── 08 - Fun with HTML5 Canvas ├── index.html └── readme.md ├── 09 - Dev Tools Domination ├── index.html └── readme.md ├── 10 - Hold Shift and Check Checkboxes ├── index.html └── readme.md ├── 11 - Custom Video Player ├── index.html ├── readme.md ├── scripts.js └── style.css ├── 12 - Key Sequence Detection ├── index.html └── readme.md ├── 13 - Slide in on Scroll ├── index.html └── readme.md ├── 14 - JavaScript References VS Copying ├── index.html └── readme.md ├── 15 - LocalStorage ├── index.html ├── readme.md └── style.css ├── 16 - Mouse Move Shadow ├── index.html └── readme.md ├── 17 - Sort Without Articles ├── index.html └── readme.md ├── 18 - Adding Up Times with Reduce ├── index.html └── readme.md ├── 19 - Webcam Fun ├── index.html ├── package.json ├── readme.md ├── scripts.js └── style.css ├── 20 - Speech Detection ├── index.html ├── package.json └── readme.md ├── 21 - Geolocation ├── index-START.html ├── package.json └── readme.md ├── 22 - Follow Along Link Highlighter ├── index.html ├── readme.md └── style.css ├── 23 - Speech Synthesis ├── index.html ├── readme.md └── style.css ├── 24 - Sticky Nav ├── index.html ├── readme.md └── style.css ├── 25 - Event Capture, Propagation, Bubbling and Once ├── index.html └── readme.md ├── 26 - Stripe Follow Along Nav ├── index.html └── readme.md ├── 27 - Click and Drag ├── index.html ├── readme.md └── style.css ├── 28 - Video Speed Controller ├── index.html ├── readme.md └── style.css ├── 29 - Countdown Timer ├── index.html ├── readme.md ├── script.js └── style.css ├── 30 - Whack A Mole ├── dirt.svg ├── index.html ├── mole.svg ├── readme.md └── style.css ├── index.html ├── readme.md ├── resources ├── JS30.png ├── favicon.ico └── img │ ├── pic1.jpg │ ├── pic2.jpg │ ├── pic3.jpg │ ├── pic4.jpg │ └── pic5.jpg └── styles.css /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | node_modules/ 4 | *.log 5 | haters/ 6 | private.md -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/background.jpg -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JS Drum Kit 7 | 8 | 9 | 10 | 11 |
12 |
13 | A 14 | clap 15 |
16 |
17 | S 18 | hihat 19 |
20 |
21 | D 22 | kick 23 |
24 |
25 | F 26 | openhat 27 |
28 |
29 | G 30 | boom 31 |
32 |
33 | H 34 | ride 35 |
36 |
37 | J 38 | snare 39 |
40 |
41 | K 42 | tom 43 |
44 |
45 | L 46 | tink 47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/readme.md: -------------------------------------------------------------------------------- 1 | # JavaScript Drum Kit 2 | The idea behind this first project is to imitate the functionality of a keyboard. Through *audio* tags we will allow the user to reproduce up to 9 different sounds. 3 | 4 | ## Notes 5 | 6 | We make use of two new concepts of HTML5: 7 | 8 | * The HTML **[data-\*][1]** attribute allows us to store custom data on any HTML element. Each `div.key` and `audio` element have a `data-key` attribute that binds them together. 9 | * The **[audio](https://developer.mozilla.org/en/docs/Web/HTML/Element/audio)** tag offers an API that makes simpler to reproduce audio files in the browser. 10 | 11 | 12 | The logic behind it, is very simple, we listen for two events: 13 | 14 | * User presses a key: get audio element, add class to the key and play it: 15 | ```javascript 16 | function keyPressed(e) { 17 | const audio = document.querySelector(`audio[data-key="${e.charCode}"]`), 18 | key = document.querySelector(`div[data-key="${e.charCode}"]`); 19 | if (!audio) return; // Not a valid key 20 | key.classList.add("playing"); 21 | audio.currentTime = 0; 22 | audio.play(); 23 | }; 24 | ``` 25 | * css-transition-end: We remove the style previously added: 26 | 27 | ```javascript 28 | function removeStyle(e) { 29 | if (e.type !== "transitionend") return; 30 | e.target.classList.remove("playing"); 31 | } 32 | ``` 33 | 34 | 35 | ## Events 36 | * **keypress:** user presses a key 37 | * **transitioned:** a css transition has completed. 38 | 39 | [1]:https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes 40 | -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/boom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/boom.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/clap.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/clap.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/hihat.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/kick.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/openhat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/openhat.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/ride.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/ride.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/snare.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/tink.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/tink.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/sounds/tom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/01 - JavaScript Drum Kit/sounds/tom.wav -------------------------------------------------------------------------------- /01 - JavaScript Drum Kit/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10px; 3 | background: url('background.jpg') bottom center; 4 | background-size: cover; 5 | } 6 | 7 | body, html { 8 | margin: 0; 9 | padding: 0; 10 | font-family: sans-serif; 11 | } 12 | 13 | .keys { 14 | display: flex; 15 | flex: 1; 16 | min-height: 100vh; 17 | align-items: center; 18 | justify-content: center; 19 | } 20 | 21 | .key { 22 | border: 4px solid black; 23 | border-radius: 5px; 24 | margin: 1rem; 25 | font-size: 1.5rem; 26 | padding: 1rem .5rem; 27 | transition: all .07s; 28 | width: 100px; 29 | text-align: center; 30 | color: white; 31 | background: rgba(0, 0, 0, 0.4); 32 | text-shadow: 0 0 5px black; 33 | } 34 | 35 | .playing { 36 | transform: scale(1.1); 37 | border-color: #ffc600; 38 | box-shadow: 0 0 10px #ffc600; 39 | } 40 | 41 | kbd { 42 | display: block; 43 | font-size: 40px; 44 | } 45 | 46 | .sound { 47 | font-size: 1.2rem; 48 | text-transform: uppercase; 49 | letter-spacing: 1px; 50 | color: #ffc600; 51 | } -------------------------------------------------------------------------------- /02 - JS + CSS Clock/DeathtoStock_QuietFrontier-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/02 - JS + CSS Clock/DeathtoStock_QuietFrontier-11.jpg -------------------------------------------------------------------------------- /02 - JS + CSS Clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JS + CSS Clock 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 | 21 | 81 | 82 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /02 - JS + CSS Clock/readme.md: -------------------------------------------------------------------------------- 1 | # JS + CSS Clock 2 | 3 | In this second project we are building an *analog* watch using JS and CSS. 4 | 5 | 6 | # Notes 7 | 8 | The most important thing about the JS code is how we do the mapping from time units to degrees: 9 | 10 | ```javascript 11 | function getTime() { 12 | const date = new Date(), 13 | lag = 90, 14 | secs = 6 * date.getSeconds() + lag, 15 | mins = 6 * date.getMinutes() + lag, 16 | hours = 30 * date.getHours() + lag; 17 | secondHand.style.transform = 'rotate(' + secs + 'deg)'; 18 | minuteHand.style.transform = 'rotate(' + mins + 'deg)'; 19 | hourHand.style.transform = `translateX(5rem) rotate(${hours}deg)`; 20 | } 21 | ``` 22 | The `lag` variable is related to the css code, where we have to define an intial rotation of 90° due the 23 | default horizontal position of elements in html: 24 | ```css 25 | .hand { 26 | width:15rem; 27 | height:6px; 28 | background:black; 29 | position: absolute; 30 | top:50%; 31 | transform-origin: 100%; 32 | transform: rotate(90deg); 33 | } 34 | ``` 35 | 36 | **NOTE:** ES6 browser compatibility by default for major browsers' last version: 37 | * Safari: 100% 38 | * Chrome, Opera: 97% 39 | * Edge: 93% 40 | * Firefox: 92% 41 | -------------------------------------------------------------------------------- /03 - CSS Variables/Death_to_stock_BMX1_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhabib/JavaScript30/abe5ed234d0a843f2bf86413f2c71118d6d16cbd/03 - CSS Variables/Death_to_stock_BMX1_10.jpg -------------------------------------------------------------------------------- /03 - CSS Variables/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Scoped CSS Variables and JS 7 | 8 | 9 | 10 |

Update CSS Variables with JS

11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 66 | 67 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /03 - CSS Variables/readme.md: -------------------------------------------------------------------------------- 1 | # CSS Variables 2 | 3 | The purpose of this challenge is to learn about the **css variables**. You may think that you have already work with them in **LESS** or **SASS** but what we are going to see here are variables 4 | that will live after preprocessing our code. 5 | 6 | ## Notes 7 | 8 | In LESS or SASS you can find something like this: 9 | 10 | ```less 11 | // Variables 12 | @link-color: #428bca; // sea blue 13 | @link-color-hover: darken(@link-color, 10%); 14 | ``` 15 | But make no mistake once they go through the preprocessor they will have a fixxed value. Instead of that, with **css variables** you can change its value during the lifecycle of your program. 16 | 17 | 18 | **So how do we work with them?** 19 | 20 | 1. We have to assign them to a component: 21 | ```css 22 | :root { 23 | --spacing: 10px; 24 | --blur: 10px; 25 | --base: white; 26 | } 27 | ``` 28 | 29 | 2. Then we use them through our styles: 30 | ```css 31 | img { 32 | width: 95%; 33 | max-width: 900px; 34 | height: auto; 35 | background-color: var(--base); 36 | padding: var(--spacing); 37 | filter: blur(var(--blur)); 38 | } 39 | ``` 40 | 41 | 3. And we also access them in our JS: 42 | ```javascript 43 | const inputs = document.querySelectorAll('.controls input'); 44 | function handleUpdate() { 45 | const data = this.value, 46 | suffix = this.dataset.sizing || '', 47 | type = this.name; 48 | document.documentElement.style.setProperty(`--${type}`, data + suffix); 49 | } 50 | 51 | inputs.forEach(input => input.addEventListener('change', handleUpdate)); 52 | ``` 53 | 54 | **NOTE**: Calling `.querySelector()` or `.querySelectorAll()` we recieve a data structure that looks like an `Array` but it is't. 55 | The `listNode` object that we obtain has a reduced API, so in case that you prefer to work with arrays there are two ways for the conversion: 56 | 57 | ```javascript 58 | const inputs = document.querySelectorAll('.controls input'); 59 | const inputsArr1 = Array.from(inputs); 60 | const inputsArr2 = [...inputs]; // ES6 spread operator 61 | ``` 62 | 63 | ## Events 64 | 65 | * **change:** input element's value chages 66 | -------------------------------------------------------------------------------- /04 - Array Cardio Day 1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Array Cardio 💪 6 | 7 | 8 |

Psst: have a look at the JavaScript Console 💁

9 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /04 - Array Cardio Day 1/readme.md: -------------------------------------------------------------------------------- 1 | # Array Cardio Day 1 2 | 3 | In this first cardio day we make use of some of the Array build-in methods: 4 | 5 | * [map](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 6 | * [sort](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 7 | * [reduce](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) 8 | 9 | ## Notes 10 | 11 | When working with **sort**, two directions: 12 | * Ascendent: 1 indicates that goes down in the array: 13 | 14 | ```javascript 15 | arr.sort((a, b) => a > b ? 1 : -1); 16 | ``` 17 | * Descendent: -1 indicates that goes up in the array: 18 | 19 | ```javascript 20 | arr.sort((a, b) => a > b ? -1 : 1); 21 | ``` 22 | 23 | When working with **reduce**, the key to be able to proccess different data types 24 | is the *initialize* value: 25 | 26 | ```javasript 27 | const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck' ], 28 | sol = data.reduce((obj, item) => { 29 | if(!obj[item]) 30 | obj[item] = 0; 31 | obj[item]++; 32 | return obj; 33 | }, {}); 34 | ``` -------------------------------------------------------------------------------- /05 - Flex Panel Gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flex Panels 💪 6 | 7 | 8 | 9 | 95 | 96 | 97 |
98 |
99 |

Hey

100 |

Let's

101 |

Dance

102 |
103 |
104 |

Give

105 |

Take

106 |

Receive

107 |
108 |
109 |

Experience

110 |

It

111 |

Today

112 |
113 |
114 |

Give

115 |

All

116 |

You can

117 |
118 |
119 |

Life

120 |

In

121 |

Motion

122 |
123 |
124 | 125 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /05 - Flex Panel Gallery/readme.md: -------------------------------------------------------------------------------- 1 | # Flex Panel Gallery 2 | 3 | In this exercise we are building a nice effect panel effect that will work great 4 | on a gallery. We make use of **flexboxes**. 5 | 6 | ## Notes 7 | 8 | The logic behind this exercise is very simple. We listen for two events: 9 | 10 | * When there is a *click* in a panel, we toggle the `.open` class from the flex panel. 11 | * And when the panel's transition ends(*transitioned*) we toggle the `.open-active` class from 12 | all the childs of the panel. It's worth mentioning how we filter the event, to get only the one 13 | that interests us: 14 | 15 | ```javascript 16 | function toggleActive(e) { 17 | if(e.propertyName.includes('flex')) 18 | this.classList.toggle('open-active'); 19 | } 20 | ``` 21 | 22 | Now the magic happens in the HTML and CSS code. So the templates structure is: 23 | 24 | ```html 25 |
26 |
27 |

Hey

28 |

Let's

29 |

Dance

30 |
31 |
32 | ... 33 |
34 | ``` 35 | 36 | And in the CSS: 37 | 38 | * `panels` is used to define the flex-container. *It is nice how he uses **vh***. 39 | * `panel` here are defined the common properties as a flex box for all the flex-pannels as 40 | well as the background properties. It also contains the transition for which we listen in 41 | the JS: 42 | 43 | ```css 44 | transition: 45 | font-size 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11), 46 | flex 0.7s cubic-bezier(0.61,-0.19, 0.7,-0.11), 47 | background 0.2s; 48 | ``` 49 | 50 | Also we define that all children of the panel are going to have a transition effect, 51 | but later only the first and last will have this `.open-active` class: 52 | 53 | ```css 54 | .panel > * { 55 | transition:transform 0.5s; 56 | } 57 | .panel > *:first-child { transform: translateY(-100%); } 58 | .panel.open-active > *:first-child { transform: translateY(0); } 59 | .panel > *:last-child { transform: translateY(100%); } 60 | .panel.open-active > *:last-child { transform: translateY(0); } 61 | ``` 62 | And last but not least the effect to make bigger a panel comes from the flex properties: 63 | 64 | ```css 65 | .panel.open { 66 | flex: 5; 67 | font-size:40px; 68 | } 69 | ``` 70 | * `panelsX` where x is between [1, 5] is how we define a particular background 71 | that each panel will have. 72 | 73 | 74 | ## Events 75 | * **click** 76 | * **transitioned:** when a CSS transition ends -------------------------------------------------------------------------------- /06 - Type Ahead/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Type Ahead 👀 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 18 |
19 | 64 | 65 | -------------------------------------------------------------------------------- /06 - Type Ahead/readme.md: -------------------------------------------------------------------------------- 1 | # Type Ahead 2 | 3 | In this new exercise making use of a new method added to the browsers, **[fetch][]**, 4 | we build a autocompletition dropdown. 5 | 6 | ## Notes 7 | 8 | First of all, at initialization we call `fetch` to grab all the data that we are going 9 | to use in the dropdown. 10 | We have to perform a mapping from the data raw data that we receive from the BackEnd, because 11 | it is sent to us as Blob: 12 | 13 | ```javascript 14 | fetch(endpoint) 15 | .then(response => response.json()) 16 | .then(myObject => cities.push(...myObject)) 17 | .catch(err => console.error(err)); 18 | ``` 19 | 20 | Then we define an auxiliar function that will help us to find a match inside our array of data 21 | `cities`. Making use or a *regular expression* we filter by cities or states that match our condition: 22 | 23 | ```javascript 24 | function findMatches(wordToMatch, cities) { 25 | return cities.filter(place => { 26 | const regex = new RegExp(wordToMatch, 'gi'); 27 | return place.city.match(regex) || place.state.match(regex); 28 | }); 29 | } 30 | ``` 31 | Finally we attach a handler for our *keyup* event. When creating the HTML code 32 | to be inserted into the `suggestion`element, we make use again of *regular expressions* 33 | to replace the values of ??????? 34 | 35 | ```javascript 36 | function displayMatches() { 37 | const matches = findMatches(this.value, cities), 38 | html = matches.map(place => { 39 | const regex = new RegExp(this.value, 'gi'), 40 | cityName = place.city.replace(regex, `${this.value}`), 41 | stateName = place.state.replace(regex, `${this.value}`); 42 | return ` 43 |
  • 44 | ${cityName}, ${stateName} 45 | ${numberWithCommas(place.population)} 46 |
  • 47 | `; 48 | }).join(''); 49 | suggestions.innerHTML = html; 50 | } 51 | ``` 52 | 53 | We also define another auxiliar function to add commas to big numbers: 54 | 55 | ```javascript 56 | function numberWithCommas(x) { 57 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 58 | } 59 | ``` 60 | 61 | **NOTE:** How the effects are defined on the css 62 | 63 | ## Events 64 | * **keyup:** we make use of it instead of **change** because it is called after the user 65 | presses a key in the input field. Otherwise it will be fired only after the user submits the 66 | form. 67 | 68 | 6. Fetch, spreading an array so push inside another, pure functions, copy arrays. -------------------------------------------------------------------------------- /06 - Type Ahead/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 | *, *:before, *:after { 9 | box-sizing: inherit; 10 | } 11 | input { 12 | width: 100%; 13 | padding:20px; 14 | } 15 | 16 | .search-form { 17 | max-width:400px; 18 | margin:50px auto; 19 | } 20 | 21 | input.search { 22 | margin: 0; 23 | text-align: center; 24 | outline:0; 25 | border: 10px solid #F7F7F7; 26 | width: 120%; 27 | left: -10%; 28 | position: relative; 29 | top: 10px; 30 | z-index: 2; 31 | border-radius: 5px; 32 | font-size: 40px; 33 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19); 34 | } 35 | 36 | 37 | .suggestions { 38 | margin: 0; 39 | padding: 0; 40 | position: relative; 41 | /*perspective:20px;*/ 42 | } 43 | .suggestions li { 44 | background:white; 45 | list-style: none; 46 | border-bottom: 1px solid #D8D8D8; 47 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.14); 48 | margin:0; 49 | padding:20px; 50 | transition:background 0.2s; 51 | display:flex; 52 | justify-content:space-between; 53 | text-transform: capitalize; 54 | } 55 | 56 | .suggestions li:nth-child(even) { 57 | transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001); 58 | background: linear-gradient(to bottom, #ffffff 0%,#EFEFEF 100%); 59 | } 60 | .suggestions li:nth-child(odd) { 61 | transform: perspective(100px) rotateX(-3deg) translateY(3px); 62 | background: linear-gradient(to top, #ffffff 0%,#EFEFEF 100%); 63 | } 64 | 65 | span.population { 66 | font-size: 15px; 67 | } 68 | 69 | 70 | .details { 71 | text-align: center; 72 | font-size: 15px; 73 | } 74 | 75 | .hl { 76 | background:#ffc600; 77 | } 78 | 79 | .love { 80 | text-align: center; 81 | } 82 | 83 | a { 84 | color:black; 85 | background:rgba(0,0,0,0.1); 86 | text-decoration: none; 87 | } 88 | -------------------------------------------------------------------------------- /07 - Array Cardio Day 2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Array Cardio 💪💪 6 | 7 | 8 |

    Psst: have a look at the JavaScript Console 💁

    9 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /07 - Array Cardio Day 2/readme.md: -------------------------------------------------------------------------------- 1 | # Array Cardio Day 2 2 | 3 | The continuation of the array workout takes us to use some new build-in methods: 4 | 5 | * [some](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/some) 6 | * [every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) 7 | * [find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) 8 | * [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) 9 | 10 | ## Notes 11 | 12 | There is a nice trick implemented in this exercise. Following a *functional-programming* 13 | style and making use fo the ES6 *spread* operator we delete an element from an array 14 | without leaving empty places: 15 | 16 | ```javascript 17 | const index = comments.findIndex(comment => comment.id === 823423); 18 | const newComments = [ 19 | ...comments.slice(0, index), 20 | ...comments.slice(index + 1, comments.length) 21 | ]; 22 | ``` -------------------------------------------------------------------------------- /08 - Fun with HTML5 Canvas/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 Canvas 6 | 7 | 8 | 9 | 56 | 57 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /08 - Fun with HTML5 Canvas/readme.md: -------------------------------------------------------------------------------- 1 | # Fun with HTML5 Canvas 2 | 3 | Making use of **HTML5 Canvas** we convert the browser in a grafitti board 😎 4 | 5 | ## Notes 6 | 7 | We start defining two objects that will represent the [canvas][1] and the [context][2]: 8 | 9 | ```javascript 10 | const canvas = document.querySelector('canvas'), 11 | ctx = canvas.getContext('2d'); 12 | ``` 13 | 14 | Then we define some properties of our canvas and context: 15 | 16 | ```javascript 17 | canvas.width = window.innerWidth; 18 | canvas.height = window.innerHeight; 19 | 20 | ctx.strokeStyle = "#BADA55"; // 21 | ctx.lineJoin = "round"; // 22 | ctx.lineCap = "round"; // 23 | ctx.lineWidth = 10; // 24 | ctx.globalCompositeOperation = 'multiply'; // 25 | ``` 26 | 27 | When the `mousedown` event is fired, the handler is called. It takes care of 28 | saving the position where the user clicked making use of the **[ES6][3]** destructuring 29 | arrays: 30 | 31 | ```javascript 32 | function mouseDown(e) { 33 | isDrawing = true; 34 | // cretes two variables 35 | [lastX, lastY] = [e.offsetX, e.offsetY]; 36 | } 37 | ``` 38 | 39 | When the `mousemove` event is fired, the handler is called. It takes care of drawing the line, 40 | updates the position of the mouse and giving a nice effect through the *hue* 41 | and the *lineWidth*: 42 | 43 | ```javascript 44 | function draw(e) { 45 | if(!isDrawing) return; 46 | ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`; 47 | // where the drawing takes place 48 | ctx.beginPath(); 49 | ctx.moveTo(lastX, lastY); 50 | ctx.lineTo(e.offsetX, e.offsetY); 51 | ctx.stroke(); 52 | 53 | [lastX, lastY] = [e.offsetX, e.offsetY]; 54 | 55 | // effects 56 | hue++; 57 | if(ctx.lineWidth === 80 || ctx.lineWidth === 1) 58 | direction = !direction; 59 | direction ? ctx.lineWidth++ : ctx.lineWidth--; 60 | } 61 | ``` 62 | 63 | ## Events 64 | 65 | * **mousemove** 66 | * **mousedown** 67 | * **mouseup** 68 | * **mouseout** 69 | 70 | [1]:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API 71 | [2]:https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D 72 | [3]:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -------------------------------------------------------------------------------- /09 - Dev Tools Domination/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Console Tricks! 6 | 7 | 8 | 9 |

    ×BREAK×DOWN×

    10 | 11 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /09 - Dev Tools Domination/readme.md: -------------------------------------------------------------------------------- 1 | # Dev Tools Domination 2 | 3 | Some nice `console.` tips to improve the way we debug our JS code. 4 | 5 | ## Notes 6 | * **console.log()** 7 | 8 | ```javascript 9 | // Interpolated 10 | console.log("Hi there, a %s", 'shit'); 11 | 12 | // Styled 13 | console.log('%c I am some edited text', 'font-size: 20px; background-color: red; text-shadow: 10px 10px 0 blue'); 14 | ``` 15 | * To filter the *logs* in the browser's developer tools: 16 | * **console.info()** 17 | * **console.warn()** 18 | * **console.error()** 19 | * **console.assert()** for testing. 20 | * **console.clear()** 21 | * **console.dir()** shows the content of a node from the HTML tag. 22 | * **console.table()** for JSON objects. 23 | * **console.count()** to count the number of times of a value. 24 | * Timers: 25 | 26 | ```javascript 27 | console.time('fetching data'); 28 | fetch('https://api.github.com/users/yhabib') 29 | .then(data => data.json()) 30 | .then(data => { 31 | console.log(data); 32 | console.timeEnd('fetching data'); // fetching data: 461.976ms 33 | }); 34 | ``` -------------------------------------------------------------------------------- /10 - Hold Shift and Check Checkboxes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 63 | 69 |
    70 |
    71 | 72 |

    This is an inbox layout.

    73 |
    74 |
    75 | 76 |

    Check one item

    77 |
    78 |
    79 | 80 |

    Hold down your Shift key

    81 |
    82 |
    83 | 84 |

    Check a lower item

    85 |
    86 |
    87 | 88 |

    Everything inbetween should also be set to checked

    89 |
    90 |
    91 | 92 |

    Try do it with out any libraries

    93 |
    94 |
    95 | 96 |

    Just regular JavaScript

    97 |
    98 |
    99 | 100 |

    Good Luck!

    101 |
    102 |
    103 | 104 |

    Don't forget to tweet your result!

    105 |
    106 |
    107 | 108 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /10 - Hold Shift and Check Checkboxes/readme.md: -------------------------------------------------------------------------------- 1 | # Hold Shift and Check Checkboxes 2 | 3 | In this exercise we try to imitate a common layout that can be found in many email clients. 4 | When a user clicks a checkbox, holds Shift, and then clicks another checkbox a few rows down, 5 | all the checkboxes inbetween those two checkboxes will be checked. 6 | 7 | ## Notes 8 | 9 | We start selecting all the inputs that are checkboxes, and binding them to the 10 | click event. 11 | 12 | ```javascript 13 | function handleCheck(e) { 14 | if (e.shiftKey && this.checked) { 15 | let flag = false; 16 | checkboxes.forEach(box => { 17 | if (box === lastCheck || box === this) flag = !flag; 18 | if (flag) box.checked = true; 19 | }) 20 | } 21 | lastCheck = this; 22 | } 23 | ``` 24 | 25 | 26 | ## Events 27 | 28 | * **click** -------------------------------------------------------------------------------- /11 - Custom Video Player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML Video Player 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 |
    14 |
    15 |
    16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 |
    24 |
    25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /11 - Custom Video Player/readme.md: -------------------------------------------------------------------------------- 1 | # Custom Video Player 2 | 3 | ## Notes: 4 | * HTML5 video tag: 5 | - Methods: 6 | - Events: Click, play, pause and timeupdate 7 | * Some 'icons' already available: 8 | * Calling a method through a variable: ►, ❚❚, ... 9 | ```javascript 10 | const method = video.paused ? 'play' : 'pause'; 11 | video[method](); 12 | ``` 13 | 14 | 15 | ## ToDo's 16 | * Maximize window button -------------------------------------------------------------------------------- /11 - Custom Video Player/scripts.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const player = document.querySelector('.player'), 3 | video = player.querySelector('.viewer'), 4 | progress = player.querySelector('.progress'), 5 | progressBar = player.querySelector('.progress__filled'), 6 | toggle = player.querySelector('.toggle'), 7 | skipButtons = player.querySelectorAll('[data-skip]'), 8 | ranges = player.querySelectorAll('.player__slider'), 9 | max = player.querySelector('.player__max'); 10 | 11 | 12 | 13 | video.addEventListener('click', togglePlay); 14 | video.addEventListener('play', updateButton); 15 | video.addEventListener('pause', updateButton); 16 | video.addEventListener('timeupdate', handleProgress); 17 | 18 | toggle.addEventListener('click', togglePlay); 19 | 20 | skipButtons.forEach(btn => btn.addEventListener('click', handleSkip)); 21 | 22 | ranges.forEach(range => range.addEventListener('change', handleRange)); 23 | ranges.forEach(range => range.addEventListener('mousemove', handleRange)); 24 | 25 | let mousedown = false; 26 | progress.addEventListener('click', scrub); 27 | progress.addEventListener('mousemove', (e) => mousedown && scrub(e)); 28 | progress.addEventListener('mousedown', () => mousedown === true); 29 | progress.addEventListener('mouseup', () => mousedown === false); 30 | 31 | max.addEventListener('click', handleMax); 32 | 33 | 34 | function togglePlay() { 35 | const method = video.paused ? 'play' : 'pause'; 36 | video[method](); 37 | } 38 | function updateButton() { 39 | const icon = this.paused ? '►' : '❚❚'; 40 | toggle.textContent = icon; 41 | } 42 | function handleSkip() { 43 | video.currentTime += +this.dataset.skip; 44 | } 45 | function handleRange() { 46 | video[this.name] = this.value; 47 | } 48 | function handleProgress() { 49 | const percent = (video.currentTime / video.duration) * 100; 50 | progressBar.style.flexBasis = `${percent}%`; 51 | } 52 | 53 | function scrub(e) { 54 | const offset = (e.offsetX / progress.offsetWidth) * video.duration; 55 | video.currentTime = offset; 56 | } 57 | 58 | function handleMax(e) { 59 | player.style.width = '100%'; 60 | console.log(player.style); 61 | // player.style.maxWidth = player.style.maxWidth === 750 62 | // Maximize = !Maximize; 63 | } 64 | })(); -------------------------------------------------------------------------------- /11 - Custom Video Player/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, *:before, *:after { 6 | box-sizing: inherit; 7 | } 8 | 9 | body { 10 | padding: 0; 11 | display:flex; 12 | background:#7A419B; 13 | min-height:100vh; 14 | background: linear-gradient(135deg, #7c1599 0%,#921099 48%,#7e4ae8 100%); 15 | background-size:cover; 16 | align-items: center; 17 | justify-content: center; 18 | } 19 | 20 | .player { 21 | max-width:750px; 22 | border:5px solid rgba(0,0,0,0.2); 23 | box-shadow:0 0 20px rgba(0,0,0,0.2); 24 | position: relative; 25 | font-size: 0; 26 | overflow: hidden; 27 | } 28 | 29 | .player__video { 30 | width: 100%; 31 | } 32 | 33 | .player__button { 34 | background:none; 35 | border:0; 36 | line-height:1; 37 | color:white; 38 | text-align: center; 39 | outline:0; 40 | padding: 0; 41 | cursor:pointer; 42 | max-width:50px; 43 | } 44 | 45 | .player__button:focus { 46 | border-color: #ffc600; 47 | } 48 | 49 | .player__slider { 50 | width:10px; 51 | height:30px; 52 | } 53 | 54 | .player__controls { 55 | display:flex; 56 | position: absolute; 57 | bottom:0; 58 | width: 100%; 59 | transform: translateY(100%) translateY(-5px); 60 | transition:all .3s; 61 | flex-wrap:wrap; 62 | background:rgba(0,0,0,0.1); 63 | } 64 | 65 | .player:hover .player__controls { 66 | transform: translateY(0); 67 | } 68 | 69 | .player:hover .progress { 70 | height:15px; 71 | } 72 | 73 | .player__controls > * { 74 | flex:1; 75 | } 76 | 77 | .progress { 78 | flex:10; 79 | position: relative; 80 | display:flex; 81 | flex-basis:100%; 82 | height:5px; 83 | transition:height 0.3s; 84 | background:rgba(0,0,0,0.5); 85 | cursor:ew-resize; 86 | } 87 | 88 | .progress__filled { 89 | width:50%; 90 | background:#ffc600; 91 | flex:0; 92 | flex-basis:0%; 93 | } 94 | 95 | /* unholy css to style input type="range" */ 96 | 97 | input[type=range] { 98 | -webkit-appearance: none; 99 | background:transparent; 100 | width: 100%; 101 | margin: 0 5px; 102 | } 103 | input[type=range]:focus { 104 | outline: none; 105 | } 106 | input[type=range]::-webkit-slider-runnable-track { 107 | width: 100%; 108 | height: 8.4px; 109 | cursor: pointer; 110 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); 111 | background: rgba(255,255,255,0.8); 112 | border-radius: 1.3px; 113 | border: 0.2px solid rgba(1, 1, 1, 0); 114 | } 115 | input[type=range]::-webkit-slider-thumb { 116 | box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); 117 | height: 15px; 118 | width: 15px; 119 | border-radius: 50px; 120 | background: #ffc600; 121 | cursor: pointer; 122 | -webkit-appearance: none; 123 | margin-top: -3.5px; 124 | box-shadow:0 0 2px rgba(0,0,0,0.2); 125 | } 126 | input[type=range]:focus::-wefbkit-slider-runnable-track { 127 | background: #bada55; 128 | } 129 | input[type=range]::-moz-range-track { 130 | width: 100%; 131 | height: 8.4px; 132 | cursor: pointer; 133 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); 134 | background: #ffffff; 135 | border-radius: 1.3px; 136 | border: 0.2px solid rgba(1, 1, 1, 0); 137 | } 138 | input[type=range]::-moz-range-thumb { 139 | box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); 140 | height: 15px; 141 | width: 15px; 142 | border-radius: 50px; 143 | background: #ffc600; 144 | cursor: pointer; 145 | } 146 | -------------------------------------------------------------------------------- /12 - Key Sequence Detection/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Key Detection 7 | 8 | 9 | 10 | 11 | 12 |

    Konami sequence for a colorful joy!!

    13 |

    Hint: The sequenze is: up, up, down, down, left, right, left, rigt, a, b 😉

    14 | 15 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /12 - Key Sequence Detection/readme.md: -------------------------------------------------------------------------------- 1 | # Key Sequence 2 | ## Konami Code 3 | The Konami Code( コナミコマンド) is a cheat code that appears in many Konami video games,[1] although the code also appears in some non-Konami games. 4 | The following sequence of buttons on the game controller to enable a kindo of cheat: 5 | [↑↑↓↓←→←→ba](http://konamicodesites.com/) 6 | 7 | ## Notes 8 | * Key Sequence Detection 9 | * Trimming and array to contain the last x elemnts: 10 | ```javascript 11 | let keys = [], 12 | code = "abcd"; 13 | keys.splice(-keys.length - 1, code.length - keys.length); 14 | ``` -------------------------------------------------------------------------------- /13 - Slide in on Scroll/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 |
    12 | 13 |

    Slide in on Scroll

    14 | 15 |

    Consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem 16 | dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora 17 | in aspernatur pariaturlores sunt esse magni, ut, dignissimos.

    18 |

    Lorem ipsum cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut 19 | asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt 20 | esse magni, ut, dignissimos.

    21 |

    Adipisicing elit. Tempore tempora rerum..

    22 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui 23 | libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas 24 | laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    25 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui 26 | libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas 27 | laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    28 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui 29 | libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas 30 | laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    31 | 32 | 33 | 34 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptates, deserunt facilis et iste corrupti omnis tenetur est. 35 | Iste ut est dicta dolor itaque adipisci, dolorum minima, veritatis earum provident error molestias. Ratione magni illo 36 | sint vel velit ut excepturi consectetur suscipit, earum modi accusamus voluptatem nostrum, praesentium numquam, reiciendis 37 | voluptas sit id quisquam. Consequatur in quis reprehenderit modi perspiciatis necessitatibus saepe, quidem, suscipit iure 38 | natus dignissimos ipsam, eligendi deleniti accusantium, rerum quibusdam fugit perferendis et optio recusandae sed ratione. 39 | Culpa, dolorum reprehenderit harum ab voluptas fuga, nisi eligendi natus maiores illum quas quos et aperiam aut doloremque 40 | optio maxime fugiat doloribus. Eum dolorum expedita quam, nesciunt

    41 | 42 | 43 | 44 |

    at provident praesentium atque quas rerum optio dignissimos repudiandae ullam illum quibusdam. Vel ad error quibusdam, illo 45 | ex totam placeat. Quos excepturi fuga, molestiae ea quisquam minus, ratione dicta consectetur officia omnis, doloribus 46 | voluptatibus? Veniam ipsum veritatis architecto, provident quas consequatur doloremque quam quidem earum expedita, ad delectus 47 | voluptatum, omnis praesentium nostrum qui aspernatur ea eaque adipisci et cumque ab? Ea voluptatum dolore itaque odio. 48 | Eius minima distinctio harum, officia ab nihil exercitationem. Tempora rem nemo nam temporibus molestias facilis minus 49 | ipsam quam doloribus consequatur debitis nesciunt tempore officiis aperiam quisquam, molestiae voluptates cum, fuga culpa. 50 | Distinctio accusamus quibusdam, tempore perspiciatis dolorum optio facere consequatur quidem ullam beatae architecto, ipsam 51 | sequi officiis dignissimos amet impedit natus necessitatibus tenetur repellendus dolor rem! Dicta dolorem, iure, facilis 52 | illo ex nihil ipsa amet officia, optio temporibus eum autem odit repellendus nisi. Possimus modi, corrupti error debitis 53 | doloribus dicta libero earum, sequi porro ut excepturi nostrum ea voluptatem nihil culpa? Ullam expedita eligendi obcaecati 54 | reiciendis velit provident omnis quas qui in corrupti est dolore facere ad hic, animi soluta assumenda consequuntur reprehenderit! 55 | Voluptate dolor nihil veniam laborum voluptas nisi pariatur sed optio accusantium quam consectetur, corrupti, sequi et 56 | consequuntur, excepturi doloremque. Tempore quis velit corporis neque fugit non sequi eaque rem hic. Facere, inventore, 57 | aspernatur. Accusantium modi atque, asperiores qui nobis soluta cumque suscipit excepturi possimus doloremque odit saepe 58 | perferendis temporibus molestiae nostrum voluptatum quis id sint quidem nesciunt culpa. Rerum labore dolor beatae blanditiis 59 | praesentium explicabo velit optio esse aperiam similique, voluptatem cum, maiores ipsa tempore. Reiciendis sed culpa atque 60 | inventore, nam ullam enim expedita consectetur id velit iusto alias vitae explicabo nemo neque odio reprehenderit soluta 61 | sint eaque. Aperiam, qui ut tenetur, voluptate doloremque officiis dicta quaerat voluptatem rerum natus magni. Eum amet 62 | autem dolor ullam.

    63 | 64 | 65 | 66 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat 67 | esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, 68 | deserunt et incidunt eveniet 69 | temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt 70 | laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, 71 | eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore 72 | illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam 73 | architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque 74 | culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, 75 | libero. Laboriosam rem, ratione. Autem blanditiis

    76 | 77 | 78 |

    laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit 79 | ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem 80 | ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem 81 | harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat 82 | ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam 83 | quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur 84 | fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, 85 | quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis 86 | blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error 87 | voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis 88 | neque.

    89 | 90 | 91 | 92 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat 93 | esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, 94 | deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, 95 | alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita 96 | dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur 97 | possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus 98 | aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam 99 | est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem 100 | quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis 101 | itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum 102 | minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime 103 | qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam 104 | illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae 105 | obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, 106 | dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim 107 | tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit 108 | vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae 109 | neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, 110 | fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

    111 |

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat 112 | esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, 113 | deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, 114 | alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita 115 | dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur 116 | possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus 117 | aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam 118 | est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem 119 | quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis 120 | itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum 121 | minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime 122 | qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam 123 | illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae 124 | obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, 125 | dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim 126 | tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit 127 | vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae 128 | neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, 129 | fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

    130 | 131 | 132 | 133 | 134 |
    135 | 136 | 174 | 175 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /13 - Slide in on Scroll/readme.md: -------------------------------------------------------------------------------- 1 | # Slide in on Scroll 2 | When scrolling through the page, the images will slide in as soon as the user reaches half the height of the imgage. These will slide out when the user keeps scrolling. 3 | 4 | ## Notes 5 | * There are some calculations to know where exactly the user is reference to an image. 6 | 7 | ```javascript 8 | // half way through the image 9 | const slideInAt = (window.scrollY + window.innerHeight) - sliderImage.height / 2; 10 | // bottom of the image 11 | const imageBottom = sliderImage.offsetTop + sliderImage.height; 12 | // is the user offset position along the image's heigh? 13 | const isHalfShown = slideInAt > sliderImage.offsetTop; 14 | // did not he already pass the image's heigh?? 15 | const isNotScrolledPast = window.scrollY < imageBottom; 16 | ``` 17 | * Debounce function limits the rate at which a function can fire. Ensures that a given task doesn't fire so often that it bricks browser performance. [More info](https://davidwalsh.name/javascript-debounce-function) 18 | 19 | ```javascript 20 | function debounce(func, wait = 20, immediate = true) { 21 | let timeout; 22 | return function () { 23 | let context = this, 24 | args = arguments, 25 | later = () => { 26 | timeout = null; 27 | if (!immediate) func.apply(context, args); 28 | }, 29 | callNow = immediate && !timeout; 30 | 31 | clearTimeout(timeout); 32 | timeout = setTimeout(later, wait); 33 | 34 | if (callNow) func.apply(context, args); 35 | }; 36 | } 37 | ``` 38 | 39 | ## Events 40 | * **scroll** 41 | -------------------------------------------------------------------------------- /14 - JavaScript References VS Copying/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JS Reference VS Copy 6 | 7 | 8 | 9 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /14 - JavaScript References VS Copying/readme.md: -------------------------------------------------------------------------------- 1 | # Objects and Arrays - JavaScript References VS Copying 2 | Comparation about how JS treats referenced and copied variables. 3 | ## Notes 4 | In JS there are two flavor of types: 5 | 6 | ### **Primitive Types** 7 | The following types are considered primitive in JavaScript: 8 | * String 9 | * Number 10 | * Boolean 11 | * Null 12 | * Undefined 13 | 14 | These types are always manipulated by **value**. This means that if we define a variable as of these types, and then we pass it to a function or create a new variable from it, this *copy* variable will will have a copy of the value of the orignal variable. Any change to one of these will have no repercusion for the other one. 15 | For example: 16 | 17 | ```javascript 18 | let age = 100, 19 | age2 = age; 20 | console.log(age === age2, age, age2); // true, 100, 100 21 | age = 200; 22 | console.log(age === age2, age, age2); // false, 200, 100 23 | ``` 24 | 25 | ### **Object Type** 26 | Leaving aside that in JS almost everything is an object, we can define that what it isn't a **primitive type** it's an **object type**. Like for example: 27 | * Object 28 | * Array 29 | * Function 30 | * Set 31 | * ... 32 | 33 | These *objects* are passed/treated by reference. This means that now what it's passed to a *copy variable* is the address of this variable instead of its value. So modifying the copy will modify the original variable. 34 | Lets see how this works with arrays: 35 | ```javascript 36 | const arr = [1, 2, 3], 37 | arrC = arr; 38 | 39 | console.log(arr === arrC, arr, arrC); //true, [1,2,3], [1,2,3] 40 | arrC[2] = 101; 41 | console.log(arr, arrC); // [1, 2, 101], [1, 2, 101] 42 | 43 | ``` 44 | 45 | The same for objects: 46 | ```javascript 47 | const person = { 48 | name: 'Bruce Wayne', 49 | city: 'Gotham City' 50 | }, 51 | hero = person; 52 | 53 | console.log(person === hero); // true 54 | 55 | hero.name = 'Batman'; 56 | console.log(person, hero) // {name: 'Batman', city: 'Gotham City'}, {name: 'Batman', city: 'Gotham City'} 57 | ``` 58 | 59 | The reason of this is that hero receives the address where person is targeting so both variable share the same object. So how can we overcome this?? How could we create a copy of *object* variables? 60 | ```javascript 61 | // arrays 62 | const arr = [1, 2, 3], 63 | arrC1 = arr.splice(), 64 | arrC2 = [].concat(arr), 65 | arrC3 = [...arr], // ES6 66 | arrC4 = Array.from(arr); 67 | 68 | // objects 69 | const obj = { val:1 , type:'Number' }, 70 | objC1 = Object.assign({}, obj); 71 | // It also allows to change some values 72 | const objC2 = Object.assign({}, obj, {val: 2}); 73 | ``` 74 | 75 | Now these copies recieve a the copied value of the original object. So changing them will not affect the original. But it is important to mark that it is a *shallow* copy, so **this is only 1 level deep**. 76 | ```javascript 77 | const arr = [[1], 2, 3], 78 | arrC1 = arr.splice(); 79 | 80 | console.log(arr, arrC1); // false 81 | arrC1[1] = 20; 82 | console.log(arr, arrC1); // [[1], 2, 3], [[1], 20, 3] 83 | 84 | arrC1[0] = 0; 85 | console.log(arr, arrC1); // [[0], 2, 3], [[0], 20, 3] 86 | 87 | // same for objects 88 | const obj = { val:1 , metadata:{ type: 'Number' } }, 89 | objC1 = Object.assign({}, obj); 90 | 91 | console.log(obj, objC1); // false 92 | objC1.val = 2; 93 | console.log(obj, objC1); // { val:1 , metadata:{ type: 'Number' } }, { val:2 , metadata:{ type: 'Number' } } 94 | 95 | objC1.metadata.new = 'new'; 96 | console.log(obj, objC1); // { val:1 , metadata:{ type: 'Number', new: 'new' } }, { val:2 , metadata:{ type: 'Number', new: 'new' } } 97 | ``` 98 | 99 | To solve that we could draw on the *lodash* cloneDeep method, that works with objects and arrays. 100 | As a **cheap** solution for objects we could also do the next(* 101 | JSON serialization and parsing is painfully slo, so native methods will be faster*): 102 | ```javascript 103 | const obj = { val:1 , metadata:{ type: 'Number' } }, 104 | objC1 = JSON.parse(JSON.stringify(obj)); 105 | ``` 106 | -------------------------------------------------------------------------------- /15 - LocalStorage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LocalStorage 7 | 8 | 9 | 10 | 11 | 15 | 16 | 18 | 19 | 21 | 23 | 25 | 27 | 29 | 30 | 31 | 32 | 33 |
    34 |

    LOCAL TAPAS

    35 |

    36 | 39 |
    40 | 41 | 42 |
    43 |
    44 | 45 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /15 - LocalStorage/readme.md: -------------------------------------------------------------------------------- 1 | # Local Storage and Event Delegation 2 | 3 | Allows the user to insert new dishes to be prepared. This dishes are going to be persistent. For that we are using the LocalStorage. 4 | We also work here with **event delegation**, that happends when we want to attach a listener to an element that is going to be created in the future, in this case the checkboxes related to each dish. 5 | 6 | ## Notes 7 | **In this exercise I did't wrap all the js code inside a IIFE becauese doing that doesn't allow to inspect the variables inside the web browser's console!!** 8 | 9 | * Working with **localStorage** to make data persistent when refreshing the browser. API: 10 | - localStorage.get(key); 11 | - localStorage.set(key, value); // It expects plain strings so if the value is an Object -> JSON.stringify(value) 12 | - localStorage.delete(key); 13 | * When working with **submit** events one has to consider that the browser is going to make a redirection to the same url plus the value of the form(GET). So in order to inspect the inhalt: 14 | - In the developer tools -> Preserve log 15 | - e.preventDefault(); // Inside the event handler. No redirection at all 16 | * Event Delegation: When listening for an event in something higher and then inside we check if it is the actually thing that we want: 17 | * A parent element is *responsible* but its children *aren't*. 18 | * He takes the responsability and then inside the event handler checks if it's correct 19 | ```javascript 20 | itemsList.addEventListener('click', toggleDone); // itemsList is an - first 21 | function toggleDone(e) { 22 | if (!e.target.matches('input')) return; // checks if its the desired child 23 | ... // delegates the handler 24 | } 25 | ``` 26 | * Using **data-index** to bind the position of the item in the array with an html component! 27 | * How to create custom checkboxes using CSS: 28 | ```css 29 | // hide original boxes 30 | .plates input { 31 | display: none; 32 | } 33 | 34 | .plates input + label:before { 35 | content: '⬜️'; 36 | margin-right: 10px; 37 | } 38 | 39 | .plates input:checked + label:before { 40 | content: '🌮'; 41 | } 42 | ``` 43 | 44 | **Note:** *If one wants to do it smarter so calling populateList will only update a new elements instead of recreating again the whole innerHtml -> AngularJs, React, ... two way bindings ...* 45 | 46 | ## Events 47 | * **submit:** in the callback the **this** object is the form 48 | * **click** 49 | 50 | ## To Do's 51 | 1. [ ] Clear button: Clears all the checkboxes 52 | -------------------------------------------------------------------------------- /15 - LocalStorage/style.css: -------------------------------------------------------------------------------- 1 | 2 | html { 3 | box-sizing: border-box; 4 | background:url('./../resources/img/pic3.jpg') center no-repeat; 5 | background-size:cover; 6 | min-height:100vh; 7 | display:flex; 8 | justify-content: center; 9 | align-items: center; 10 | text-align: center; 11 | font-family: Futura,"Trebuchet MS",Arial,sans-serif 12 | } 13 | *, *:before, *:after {box-sizing: inherit; } 14 | 15 | svg { 16 | fill:white; 17 | background: rgba(0,0,0,0.1); 18 | padding: 20px; 19 | border-radius: 50%; 20 | width:200px; 21 | margin-bottom: 50px; 22 | } 23 | 24 | .wrapper { 25 | padding: 20px; 26 | max-width: 350px; 27 | background: rgba(255,255,255,0.95); 28 | box-shadow: 0 0 0 10px rgba(0,0,0,0.1); 29 | } 30 | 31 | h2 { 32 | text-align: center; 33 | margin: 0; 34 | font-weight: 200; 35 | } 36 | 37 | .plates { 38 | margin: 0; 39 | padding: 0; 40 | text-align: left; 41 | list-style: none; 42 | } 43 | 44 | .plates li { 45 | border-bottom: 1px solid rgba(0,0,0,0.2); 46 | padding: 10px 0; 47 | font-weight: 100; 48 | display: flex; 49 | } 50 | 51 | .plates label { 52 | flex:1; 53 | cursor: pointer; 54 | 55 | } 56 | 57 | .plates input { 58 | display: none; 59 | } 60 | 61 | .plates input + label:before { 62 | content: '⬜️'; 63 | margin-right: 10px; 64 | } 65 | 66 | .plates input:checked + label:before { 67 | content: '🌮'; 68 | } 69 | 70 | .add-items { 71 | margin-top: 20px; 72 | } 73 | 74 | .add-items input { 75 | padding:10px; 76 | outline:0; 77 | border:1px solid rgba(0,0,0,0.1); 78 | } 79 | -------------------------------------------------------------------------------- /16 - Mouse Move Shadow/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mouse Shadow 6 | 7 | 8 | 9 |
    10 |

    🔥WOAH!

    11 |
    12 | 13 | 32 | 33 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /16 - Mouse Move Shadow/readme.md: -------------------------------------------------------------------------------- 1 | # Text Shadow Mouse Move Effect 2 | When the user scrolls a text shadow effect is attached to the *headear* inside a *div* component 3 | 4 | ## Notes 5 | * HTML gloabl attribute **contenteditable** defines that the content of an element is editable. 6 | 7 | ```html 8 |

    🔥WOAH!

    9 | ``` 10 | * Working with **events**: 11 | - **this** represents the the thing that you are listen on for the event (always the same) 12 | - **e.target** represents the thing that actually triggered on the event (the same element than above or also could be its children) 13 | ```javascript 14 | // When they are not the same we have to calculate 15 | if( this !== e.target) { 16 | x = x + e.target.offsetLeft; 17 | y = y + e.target.offsetTop; 18 | } 19 | ``` 20 | - Some properties for the measures: 21 | - **this.offsetHeight**, **this.offsetWidth** 22 | - **e.offsetX**, **e.offsetY** 23 | - **e.target.offsetLeft**, **e.target.offsetTop** 24 | ```javascript 25 | // Width & height properties of the 'hero' div in relation to the window object 26 | const { offsetWidth: width, offsetHeight: height } = this; 27 | // Distance of the mouse from the event's target on both axis 28 | let {offsetX: x, offsetY: y } = e; 29 | // If the element that is the current target of the event differs from the event's originating target, 30 | // increment the values of the two previously declared variables by the distance between the originating target and the current target on both axis 31 | if( this !== e.target) { 32 | x = x + e.target.offsetLeft; 33 | y = y + e.target.offsetTop; 34 | } 35 | ``` 36 | - **walk** is used to calculate the stretch distance for the element's shadow on both axis. 37 | ```javascript 38 | const walk = 100; // 100px 39 | const xWalk = (x / width * walk) - (walk / 2); // Normaliza and then rest half the walk 40 | const yWalk = (y / height * walk) - (walk / 2); 41 | ``` 42 | * ES6 destruturing: 43 | 44 | ```javascript 45 | const width = this.offsetWidth, 46 | height = this.offsetHeight; 47 | const { offsetWidth: width, offsetHeight: height } = hero; 48 | ``` 49 | 50 | ## Events 51 | * **mousemove** 52 | 53 | -------------------------------------------------------------------------------- /17 - Sort Without Articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sort Without Articles 6 | 7 | 8 | 9 | 45 | 46 | 47 | 48 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /17 - Sort Without Articles/readme.md: -------------------------------------------------------------------------------- 1 | # Sort Without Articles 2 | 3 | This one was a short one, the idea was to sort an array of Bands without taking care of the article. 4 | 5 | ## Notes 6 | * How to strip a word with **regular expressions**: 7 | 8 | ```javascript 9 | function strip(bandName) { 10 | return bandName.replace(/^(a |the |an )/i, '').trim(); 11 | } 12 | ``` 13 | * Sorting and coupling to the html element: 14 | 15 | ```javascript 16 | const sortedBands = bands.sort((a, b) => strip(a) > strip(b) ? 1 : -1); 17 | document.querySelector('#bands').innerHTML = sortedBands.map(band => `
  • ${band}
  • `).join(''); 18 | ``` 19 | -------------------------------------------------------------------------------- /18 - Adding Up Times with Reduce/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Videos 6 | 7 | 8 |