├── .gitignore ├── 01-JS-Drum-Kit ├── index.html ├── package.json ├── sounds │ ├── boom.wav │ ├── clap.wav │ ├── hihat.wav │ ├── kick.wav │ ├── openhat.wav │ ├── ride.wav │ ├── snare.wav │ ├── tink.wav │ └── tom.wav └── src │ ├── index.js │ └── styles.css ├── 02-JS-CSS-Clock ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 03-CSS-Variables ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 04-Array-Cardio-1 ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 05-Flex-Gallery ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 06-Type-Ahead ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 07-Array-Cardio-2 ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 08-HTML5-Canvas ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 09-Dev-Tools ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 10-Multiple-Check-Shift ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 11-Custom-Video-Player ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 12-Key-Sequence-Detection ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 13-Slide-In-On-Scroll ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 14-JS-Reference-Vs-Copy ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 15-Localstorage ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 16-Mousemove-Shadow ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 17-Sort-Without-Articles ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 18-Add-Time-With-Reduce ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 19-Webcam-Fun ├── .cache │ ├── 19 │ │ └── 2a340c057017172252c7a98c05d581.json │ ├── 57 │ │ └── 730c4c4fbb17905544f6301244eb4f.json │ ├── 99 │ │ └── 9d1e0ef9756b6671230ebd5667ef53.json │ ├── 1c │ │ └── bbc204f36037adc9e7df523c6762b0.json │ ├── ce │ │ └── cfe6d71944082b11df6af23fa13790.json │ └── eb │ │ └── 359863811fcd8b8e7c1af4f52a0b8b.json ├── dist │ ├── index.html │ ├── src.a2b27638.js │ ├── src.a2b27638.js.map │ ├── styles.dd855970.css │ ├── styles.dd855970.css.map │ ├── styles.dd855970.js │ └── styles.dd855970.js.map ├── index.html ├── package-lock.json ├── package.json ├── snap.mp3 └── src │ ├── index.js │ └── styles.css ├── 20-Speech-Recognition ├── index.html ├── package-lock.json ├── package.json └── src │ ├── index.js │ └── styles.css ├── 21-Geolocation ├── index.html ├── package-lock.json ├── package.json └── src │ ├── index.js │ └── styles.css ├── 22-Follow-Along-Link ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 23-Speech-Synthesis ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 24-Sticky-Nav ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 25-EventCapture-Propogation-Bubbling ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 26-Stripe-Nav ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 27-Click-Drag-Scroll ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 28-Video-Speed-Controller ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 29-Countdown-Timer ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── 30-Whack-A-Mole ├── index.html ├── package.json └── src │ ├── index.js │ └── styles.css ├── LICENSE ├── README.md ├── assets ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── asteroids.jpg ├── celebration.png ├── dirt.svg ├── fancy-pants.jpg ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── green-goblin.png ├── manifest.json ├── mole.svg ├── ocean.jpg ├── og.png ├── plaid.jpg ├── shattered-island.gif ├── special-delivery.jpg └── wild-sea.png ├── common.css ├── index.html ├── package-lock.json ├── package.json ├── sitemap.xml └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | dist 35 | .cache 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # next.js build output 63 | .next 64 | -------------------------------------------------------------------------------- /01-JS-Drum-Kit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JS Drum Kit 6 | 7 | 8 | 12 | 17 | 23 | 29 | 30 | 31 | 32 |
33 |
#1
34 |
of JavaScript30
35 |
36 |
37 |
38 |

JS Drum Kit

39 |
40 |
41 | A 42 | clap 43 |
44 |
45 | S 46 | hihat 47 |
48 |
49 | D 50 | kick 51 |
52 |
53 | F 54 | openhat 55 |
56 |
57 | G 58 | boom 59 |
60 |
61 | H 62 | ride 63 |
64 |
65 | J 66 | snare 67 |
68 |
69 | K 70 | tom 71 |
72 |
73 | L 74 | tink 75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /01-JS-Drum-Kit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "01-js-drum-kit", 3 | "version": "1.0.0", 4 | "description": "Simple Parcel Sandbox", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/boom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/boom.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/clap.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/clap.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/hihat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/hihat.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/kick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/kick.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/openhat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/openhat.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/ride.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/ride.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/snare.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/snare.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/tink.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/tink.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/sounds/tom.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/01-JS-Drum-Kit/sounds/tom.wav -------------------------------------------------------------------------------- /01-JS-Drum-Kit/src/index.js: -------------------------------------------------------------------------------- 1 | const keyCodes = { 2 | 'A': 65, 3 | 'S': 83, 4 | 'D': 68, 5 | 'F': 70, 6 | 'G': 71, 7 | 'H': 72, 8 | 'J': 74, 9 | 'K': 75, 10 | 'L': 76, 11 | }; 12 | 13 | function removeTransition(e) { 14 | if (e.propertyName !== 'transform') return; 15 | e.target.classList.remove('playing'); 16 | } 17 | 18 | function playSound(e) { 19 | const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`); 20 | const key = document.querySelector(`div[data-key="${e.keyCode}"]`); 21 | if (!audio) return; 22 | 23 | key.classList.add('playing'); 24 | audio.currentTime = 0; 25 | audio.play(); 26 | } 27 | 28 | function playSoundOnTouch(e) { 29 | // console.log(e); 30 | const audio = document.querySelector(`audio[data-key="${keyCodes[e.path[0].innerText]}"]`); 31 | const key = document.querySelector(`div[data-key="${keyCodes[e.path[0].innerText]}"]`); 32 | if (!audio) return; 33 | 34 | key.classList.add('playing'); 35 | audio.currentTime = 0; 36 | audio.play(); 37 | } 38 | 39 | const keys = Array.from(document.querySelectorAll('.key')); 40 | keys.forEach((key) => { 41 | key.addEventListener('transitionend', removeTransition); 42 | key.addEventListener('touchstart', playSoundOnTouch, false); 43 | key.addEventListener('click', playSoundOnTouch); 44 | }); 45 | window.addEventListener('keydown', playSound); 46 | -------------------------------------------------------------------------------- /02-JS-CSS-Clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JS + CSS Clock 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
29 |
#2
30 |
of JavaScript30
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /02-JS-CSS-Clock/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parcel-sandbox", 3 | "version": "1.0.0", 4 | "description": "Simple Parcel Sandbox", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | } 15 | } -------------------------------------------------------------------------------- /02-JS-CSS-Clock/src/index.js: -------------------------------------------------------------------------------- 1 | const secondHand = document.querySelector(".second-hand"); 2 | const minuteHand = document.querySelector(".min-hand"); 3 | const hourHand = document.querySelector(".hour-hand"); 4 | 5 | function setDate() { 6 | const now = new Date(); 7 | 8 | const seconds = now.getSeconds(); 9 | const secondDegrees = (seconds / 60) * 360 + 90; 10 | secondHand.style.transform = `rotate(${secondDegrees}deg)`; 11 | 12 | const minutes = now.getMinutes(); 13 | const minuteDegrees = (minutes / 60) * 360 + 90; 14 | minuteHand.style.transform = `rotate(${minuteDegrees}deg)`; 15 | 16 | const hours = now.getHours(); 17 | const hourDegrees = (hours / 12) * 360 + 90; 18 | hourHand.style.transform = `rotate(${hourDegrees}deg)`; 19 | } 20 | 21 | setInterval(setDate, 1000); 22 | -------------------------------------------------------------------------------- /02-JS-CSS-Clock/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | /* background: #018ded; */ 3 | background-color: #018ded; 4 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 304 304' width='304' height='304'%3E%3Cpath fill='%2313042b' fill-opacity='0.1' d='M44.1 224a5 5 0 1 1 0 2H0v-2h44.1zm160 48a5 5 0 1 1 0 2H82v-2h122.1zm57.8-46a5 5 0 1 1 0-2H304v2h-42.1zm0 16a5 5 0 1 1 0-2H304v2h-42.1zm6.2-114a5 5 0 1 1 0 2h-86.2a5 5 0 1 1 0-2h86.2zm-256-48a5 5 0 1 1 0 2H0v-2h12.1zm185.8 34a5 5 0 1 1 0-2h86.2a5 5 0 1 1 0 2h-86.2zM258 12.1a5 5 0 1 1-2 0V0h2v12.1zm-64 208a5 5 0 1 1-2 0v-54.2a5 5 0 1 1 2 0v54.2zm48-198.2V80h62v2h-64V21.9a5 5 0 1 1 2 0zm16 16V64h46v2h-48V37.9a5 5 0 1 1 2 0zm-128 96V208h16v12.1a5 5 0 1 1-2 0V210h-16v-76.1a5 5 0 1 1 2 0zm-5.9-21.9a5 5 0 1 1 0 2H114v48H85.9a5 5 0 1 1 0-2H112v-48h12.1zm-6.2 130a5 5 0 1 1 0-2H176v-74.1a5 5 0 1 1 2 0V242h-60.1zm-16-64a5 5 0 1 1 0-2H114v48h10.1a5 5 0 1 1 0 2H112v-48h-10.1zM66 284.1a5 5 0 1 1-2 0V274H50v30h-2v-32h18v12.1zM236.1 176a5 5 0 1 1 0 2H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30a5 5 0 1 1 0-2H274v44.1a5 5 0 1 1-2 0V146h-10.1zm-64 96a5 5 0 1 1 0-2H208v-80h16v-14h-42.1a5 5 0 1 1 0-2H226v18h-16v80h-12.1zm86.2-210a5 5 0 1 1 0 2H272V0h2v32h10.1zM98 101.9V146H53.9a5 5 0 1 1 0-2H96v-42.1a5 5 0 1 1 2 0zM53.9 34a5 5 0 1 1 0-2H80V0h2v34H53.9zm60.1 3.9V66H82v64H69.9a5 5 0 1 1 0-2H80V64h32V37.9a5 5 0 1 1 2 0zM101.9 82a5 5 0 1 1 0-2H128V37.9a5 5 0 1 1 2 0V82h-28.1zm16-64a5 5 0 1 1 0-2H146v44.1a5 5 0 1 1-2 0V18h-26.1zm102.2 270a5 5 0 1 1 0 2H98v14h-2v-16h124.1zM242 149.9V160h16v34h-16v62h48v48h-2v-46h-48v-66h16v-30h-16v-12.1a5 5 0 1 1 2 0zM53.9 18a5 5 0 1 1 0-2H64V2H48V0h18v18H53.9zm112 32a5 5 0 1 1 0-2H192V0h50v2h-48v48h-28.1zm-48-48a5 5 0 0 1-9.8-2h2.07a3 3 0 1 0 5.66 0H178v34h-18V21.9a5 5 0 1 1 2 0V32h14V2h-58.1zm0 96a5 5 0 1 1 0-2H137l32-32h39V21.9a5 5 0 1 1 2 0V66h-40.17l-32 32H117.9zm28.1 90.1a5 5 0 1 1-2 0v-76.51L175.59 80H224V21.9a5 5 0 1 1 2 0V82h-49.59L146 112.41v75.69zm16 32a5 5 0 1 1-2 0v-99.51L184.59 96H300.1a5 5 0 0 1 3.9-3.9v2.07a3 3 0 0 0 0 5.66v2.07a5 5 0 0 1-3.9-3.9H185.41L162 121.41v98.69zm-144-64a5 5 0 1 1-2 0v-3.51l48-48V48h32V0h2v50H66v55.41l-48 48v2.69zM50 53.9v43.51l-48 48V208h26.1a5 5 0 1 1 0 2H0v-65.41l48-48V53.9a5 5 0 1 1 2 0zm-16 16V89.41l-34 34v-2.82l32-32V69.9a5 5 0 1 1 2 0zM12.1 32a5 5 0 1 1 0 2H9.41L0 43.41V40.6L8.59 32h3.51zm265.8 18a5 5 0 1 1 0-2h18.69l7.41-7.41v2.82L297.41 50H277.9zm-16 160a5 5 0 1 1 0-2H288v-71.41l16-16v2.82l-14 14V210h-28.1zm-208 32a5 5 0 1 1 0-2H64v-22.59L40.59 194H21.9a5 5 0 1 1 0-2H41.41L66 216.59V242H53.9zm150.2 14a5 5 0 1 1 0 2H96v-56.6L56.6 162H37.9a5 5 0 1 1 0-2h19.5L98 200.6V256h106.1zm-150.2 2a5 5 0 1 1 0-2H80v-46.59L48.59 178H21.9a5 5 0 1 1 0-2H49.41L82 208.59V258H53.9zM34 39.8v1.61L9.41 66H0v-2h8.59L32 40.59V0h2v39.8zM2 300.1a5 5 0 0 1 3.9 3.9H3.83A3 3 0 0 0 0 302.17V256h18v48h-2v-46H2v42.1zM34 241v63h-2v-62H0v-2h34v1zM17 18H0v-2h16V0h2v18h-1zm273-2h14v2h-16V0h2v16zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1A5.02 5.02 0 0 1 6 97a5 5 0 0 1-6 4.9v-2.07a3 3 0 1 0 0-5.66V92.1zM80 272h2v32h-2v-32zm37.9 32h-2.07a3 3 0 0 0-5.66 0h-2.07a5 5 0 0 1 9.8 0zM5.9 0A5.02 5.02 0 0 1 0 5.9V3.83A3 3 0 0 0 3.83 0H5.9zm294.2 0h2.07A3 3 0 0 0 304 3.83V5.9a5 5 0 0 1-3.9-5.9zm3.9 300.1v2.07a3 3 0 0 0-1.83 1.83h-2.07a5 5 0 0 1 3.9-3.9zM97 100a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-48 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 96a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-144a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm96 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM49 36a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-32 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM33 68a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 240a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm80-176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 48a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm112 176a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-16 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 180a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0 16a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm0-32a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM17 84a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm32 64a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm16-16a3 3 0 1 0 0-6 3 3 0 0 0 0 6z'%3E%3C/path%3E%3C/svg%3E"); 5 | font-family: "helvetica neue"; 6 | text-align: center; 7 | font-size: 10px; 8 | } 9 | body { 10 | margin: 0; 11 | font-size: 2rem; 12 | display: flex; 13 | flex: 1; 14 | min-height: 100vh; 15 | align-items: center; 16 | } 17 | .clock { 18 | width: 30rem; 19 | height: 30rem; 20 | border: 20px solid white; 21 | border-radius: 50%; 22 | margin: 50px auto; 23 | position: relative; 24 | padding: 2rem; 25 | box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1), inset 0 0 0 3px #efefef, 26 | inset 0 0 10px black, 0 0 10px rgba(0, 0, 0, 0.2); 27 | } 28 | .clock-face { 29 | position: relative; 30 | width: 100%; 31 | height: 100%; 32 | transform: translateY(-3px); /* account for the height of the clock hands */ 33 | } 34 | .hand { 35 | width: 50%; 36 | height: 6px; 37 | background: black; 38 | position: absolute; 39 | top: 50%; 40 | transform-origin: 100%; 41 | transform: rotate(90deg); 42 | transition: all 0.05s; 43 | transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1); 44 | border-radius: 5px; 45 | } 46 | 47 | .hour-hand { 48 | width: 25%; 49 | margin-left: 25%; 50 | background: rgb(0, 255, 221); 51 | } 52 | 53 | .min-hand { 54 | width: 40%; 55 | margin-left: 10%; 56 | background: rgb(128, 51, 0); 57 | } 58 | 59 | .inner-circle { 60 | top: 50%; 61 | position: absolute; 62 | margin-left: 48%; 63 | width: 10px; 64 | height: 10px; 65 | border: 3px solid balck; 66 | border-radius: 50%; 67 | background: white; 68 | } 69 | -------------------------------------------------------------------------------- /03-CSS-Variables/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scoped CSS Variables and JS 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
29 |
#3
30 |
of JavaScript30
31 |
32 |
33 |

Update CSS Variables with JS

34 | 35 |
36 | 37 | 46 | 47 | 48 | 57 | 58 | 59 | 60 | 61 | 62 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /03-CSS-Variables/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parcel-sandbox", 3 | "version": "1.0.0", 4 | "description": "Simple Parcel Sandbox", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | } 15 | } -------------------------------------------------------------------------------- /03-CSS-Variables/src/index.js: -------------------------------------------------------------------------------- 1 | const inputs = document.querySelectorAll(".controls input"); 2 | 3 | function handleUpdate() { 4 | const suffix = this.dataset.sizing || ""; 5 | document.documentElement.style.setProperty( 6 | `--${this.name}`, 7 | this.value + suffix 8 | ); 9 | } 10 | 11 | inputs.forEach(input => input.addEventListener("change", handleUpdate)); 12 | inputs.forEach(input => input.addEventListener("mousemove", handleUpdate)); 13 | -------------------------------------------------------------------------------- /03-CSS-Variables/src/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --base: #ffc600; 3 | --spacing: 10px; 4 | --blur: 10px; 5 | --border-radius: 10px; 6 | } 7 | 8 | body { 9 | text-align: center; 10 | background-image: url('../../assets/fancy-pants.jpg'); 11 | background-color: #242329; 12 | color: white; 13 | font-family: 'helvetica neue', sans-serif; 14 | font-weight: 100; 15 | font-size: 50px; 16 | } 17 | .controls { 18 | margin-bottom: 50px; 19 | } 20 | input { 21 | width: 100px; 22 | } 23 | 24 | img { 25 | padding: var(--spacing); 26 | background: var(--base); 27 | filter: blur(var(--blur)); 28 | border-radius: var(--border-radius); 29 | background-size: cover; 30 | } 31 | 32 | .hl { 33 | color: var(--base); 34 | } 35 | -------------------------------------------------------------------------------- /04-Array-Cardio-1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Array Cardio 💪 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
29 |
#4
30 |
of JavaScript30
31 |
32 |
33 |

Psst: have a look at the JavaScript Console 💁

34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /04-Array-Cardio-1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "array-cardio", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /04-Array-Cardio-1/src/index.js: -------------------------------------------------------------------------------- 1 | const inventors = [ 2 | { first: "Albert", last: "Einstein", year: 1879, passed: 1955 }, 3 | { first: "Isaac", last: "Newton", year: 1643, passed: 1727 }, 4 | { first: "Galileo", last: "Galilei", year: 1564, passed: 1642 }, 5 | { first: "Marie", last: "Curie", year: 1867, passed: 1934 }, 6 | { first: "Johannes", last: "Kepler", year: 1571, passed: 1630 }, 7 | { first: "Nicolaus", last: "Copernicus", year: 1473, passed: 1543 }, 8 | { first: "Max", last: "Planck", year: 1858, passed: 1947 }, 9 | { first: "Katherine", last: "Blodgett", year: 1898, passed: 1979 }, 10 | { first: "Ada", last: "Lovelace", year: 1815, passed: 1852 }, 11 | { first: "Sarah E.", last: "Goode", year: 1855, passed: 1905 }, 12 | { first: "Lise", last: "Meitner", year: 1878, passed: 1968 }, 13 | { first: "Hanna", last: "Hammarström", year: 1829, passed: 1909 } 14 | ]; 15 | 16 | const people = [ 17 | "Beck, Glenn", 18 | "Becker, Carl", 19 | "Beckett, Samuel", 20 | "Beddoes, Mick", 21 | "Beecher, Henry", 22 | "Beethoven, Ludwig", 23 | "Begin, Menachem", 24 | "Belloc, Hilaire", 25 | "Bellow, Saul", 26 | "Benchley, Robert", 27 | "Benenson, Peter", 28 | "Ben-Gurion, David", 29 | "Benjamin, Walter", 30 | "Benn, Tony", 31 | "Bennington, Chester", 32 | "Benson, Leana", 33 | "Bent, Silas", 34 | "Bentsen, Lloyd", 35 | "Berger, Ric", 36 | "Bergman, Ingmar", 37 | "Berio, Luciano", 38 | "Berle, Milton", 39 | "Berlin, Irving", 40 | "Berne, Eric", 41 | "Bernhard, Sandra", 42 | "Berra, Yogi", 43 | "Berry, Halle", 44 | "Berry, Wendell", 45 | "Bethea, Erin", 46 | "Bevan, Aneurin", 47 | "Bevel, Ken", 48 | "Biden, Joseph", 49 | "Bierce, Ambrose", 50 | "Biko, Steve", 51 | "Billings, Josh", 52 | "Biondo, Frank", 53 | "Birrell, Augustine", 54 | "Black, Elk", 55 | "Blair, Robert", 56 | "Blair, Tony", 57 | "Blake, William" 58 | ]; 59 | 60 | // Array.protot ype.filter() 61 | // 1. Filter the list of inventors for those who were born in the 1500's 62 | const fifteen = inventors.filter( 63 | inventor => inventor.year >= 1500 && inventor.year < 1600 64 | ); 65 | console.table(fifteen); 66 | 67 | // Array.prototype.map() 68 | // 2. Give us an array of the inventors' first and last names 69 | const fullNames = inventors.map( 70 | inventor => `${inventor.first} ${inventor.last}` 71 | ); 72 | console.log(fullNames); 73 | 74 | // Array.prototype.sort() 75 | // 3. Sort the inventors by birthdate, oldest to youngest 76 | const sorted = inventors.sort((a, b) => (a.year > b.year ? 1 : -1)); 77 | console.table(sorted); 78 | 79 | // Array.prototype.reduce() 80 | // 4. How many years did all the inventors live? 81 | const totalYears = inventors.reduce( 82 | (total, inventor) => total + (inventor.passed - inventor.year), 83 | 0 84 | ); 85 | console.log(totalYears); 86 | 87 | // 5. Sort the inventors by years lived 88 | const oldest = inventors.sort((a, b) => { 89 | const lastGuy = a.passed - a.year; 90 | const nextGuy = b.passed - b.year; 91 | return lastGuy > nextGuy ? -1 : 1; 92 | }); 93 | console.table(oldest); 94 | 95 | // 6. create a list of Boulevards in Paris that contain 'de' anywhere in the name 96 | // https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris 97 | 98 | // const category = document.querySelector(".mw-category"); 99 | 100 | // const links = category.querySelectorAll('a'); 101 | // the above returns a NodeList, not an array. NodeList is like an array but doesn't contain all of the array methods. 102 | // We can convert to array in two ways. 103 | //1. const links = [...category.querySelectorAll('a')] 104 | //2. below 105 | 106 | // const links = Array.from(category.querySelectorAll("a")); 107 | 108 | // const de = links 109 | // .map(link => link.textContent) 110 | // .filter(streetName => streetName.includes("de")); 111 | 112 | // 7. sort Exercise 113 | // Sort the people alphabetically by last name 114 | const alpha = people.sort((lastOne, nextOne) => { 115 | const [aLast, aFirst] = lastOne.split(", "); 116 | const [bLast, bFirst] = nextOne.split(", "); 117 | return aLast > bLast ? 1 : -1; 118 | }); 119 | console.log(alpha); 120 | 121 | // 8. Reduce Exercise 122 | // Sum up the instances of each of these 123 | const data = [ 124 | "car", 125 | "car", 126 | "truck", 127 | "truck", 128 | "bike", 129 | "walk", 130 | "car", 131 | "van", 132 | "bike", 133 | "walk", 134 | "car", 135 | "van", 136 | "car", 137 | "truck" 138 | ]; 139 | 140 | const transportation = data.reduce((obj, item) => { 141 | if (!obj[item]) { 142 | obj[item] = 0; 143 | } 144 | obj[item]++; 145 | return obj; 146 | }, {}); 147 | 148 | console.log(transportation); 149 | -------------------------------------------------------------------------------- /04-Array-Cardio-1/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('../../assets/wild-sea.png'); 3 | background-color: #FFA23B; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | height: 100vh; 8 | font-family: monospace; 9 | font-size: large; 10 | font-weight: bolder; 11 | } -------------------------------------------------------------------------------- /05-Flex-Gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flex Panels 💪 - JavaScript30 - Ayush Gupta 6 | 11 | 12 | 13 | 18 | 24 | 30 | 31 | 32 | 33 |
34 |
#5
35 |
of JavaScript30
36 |
37 |
38 |
39 |
40 |

Hey

41 |

Let's

42 |

Dance

43 |
44 |
45 |

Give

46 |

Take

47 |

Receive

48 |
49 |
50 |

Experience

51 |

It

52 |

Today

53 |
54 |
55 |

Give

56 |

All

57 |

You can

58 |
59 |
60 |

Life

61 |

In

62 |

Motion

63 |
64 |
65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /05-Flex-Gallery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flex-panel-gallery", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /05-Flex-Gallery/src/index.js: -------------------------------------------------------------------------------- 1 | const panels = document.querySelectorAll(".panel"); 2 | 3 | function toggleOpen() { 4 | this.classList.toggle("open"); 5 | } 6 | 7 | function toggleActive(e) { 8 | // this.classList.toggle("open-active"); 9 | //we didn't used above statement as there are multiple transition events happening. 10 | if (e.propertyName.includes("flex")) { 11 | this.classList.toggle("open-active"); 12 | } 13 | } 14 | 15 | panels.forEach(panel => panel.addEventListener("click", toggleOpen)); 16 | panels.forEach(panel => panel.addEventListener("transitionend", toggleActive)); 17 | -------------------------------------------------------------------------------- /05-Flex-Gallery/src/styles.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 | body { 10 | margin: 0; 11 | } 12 | 13 | *, 14 | *:before, 15 | *:after { 16 | box-sizing: inherit; 17 | } 18 | 19 | .panels { 20 | min-height: 100vh; 21 | overflow: hidden; 22 | display: flex; 23 | } 24 | 25 | .panel { 26 | background: #6b0f9c; 27 | box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1); 28 | color: white; 29 | text-align: center; 30 | align-items: center; 31 | /* Safari transitionend event.propertyName === flex */ 32 | /* Chrome + FF transitionend event.propertyName === flex-grow */ 33 | transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), 34 | flex 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), background 0.2s; 35 | font-size: 20px; 36 | background-size: cover; 37 | background-position: center; 38 | flex: 1; 39 | display: flex; 40 | flex-direction: column; 41 | justify-content: center; 42 | } 43 | 44 | .panel1 { 45 | background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500); 46 | } 47 | .panel2 { 48 | background-image: url(https://source.unsplash.com/rFKUFzjPYiQ/1500x1500); 49 | } 50 | .panel3 { 51 | background-image: url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d); 52 | } 53 | .panel4 { 54 | background-image: url(https://source.unsplash.com/ITjiVXcwVng/1500x1500); 55 | } 56 | .panel5 { 57 | background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500); 58 | } 59 | 60 | /* Flex Children */ 61 | .panel > * { 62 | margin: 0; 63 | width: 100%; 64 | transition: transform 0.5s; 65 | flex: 1 0 auto; 66 | display: flex; 67 | justify-content: center; 68 | align-items: center; 69 | } 70 | 71 | .panel > *:first-child { 72 | transform: translateY(-100%); 73 | } 74 | .panel.open-active > *:first-child { 75 | transform: translateY(0); 76 | } 77 | .panel > *:last-child { 78 | transform: translateY(100%); 79 | } 80 | .panel.open-active > *:last-child { 81 | transform: translateY(0); 82 | } 83 | 84 | .panel p { 85 | text-transform: uppercase; 86 | font-family: "Amatic SC", cursive; 87 | text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45); 88 | font-size: 2em; 89 | } 90 | 91 | .panel p:nth-child(2) { 92 | font-size: 4em; 93 | } 94 | .panel.open { 95 | font-size: 40px; 96 | flex: 5; 97 | } 98 | -------------------------------------------------------------------------------- /06-Type-Ahead/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Ahead 👀 - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
30 |
#6
31 |
of JavaScript30
32 |
33 |
34 |
35 | 36 | 40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /06-Type-Ahead/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ajax-type-ahead", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /06-Type-Ahead/src/index.js: -------------------------------------------------------------------------------- 1 | const endpoint = 2 | "https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json"; 3 | const cities = []; 4 | 5 | fetch(endpoint) 6 | .then(blob => blob.json()) 7 | .then(data => cities.push(...data)); 8 | 9 | function findMatches(wordToMatch, cities) { 10 | return cities.filter(place => { 11 | const regex = new RegExp(wordToMatch, "gi"); 12 | return place.city.match(regex) || place.state.match(regex); 13 | }); 14 | } 15 | 16 | function numberWithCommas(x) { 17 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 18 | } 19 | 20 | function displayMatches() { 21 | const matchArray = findMatches(this.value, cities); 22 | const html = matchArray 23 | .map(place => { 24 | const regex = new RegExp(this.value, "gi"); 25 | const cityName = place.city.replace( 26 | regex, 27 | `${this.value}` 28 | ); 29 | const stateName = place.state.replace( 30 | regex, 31 | `${this.value}` 32 | ); 33 | 34 | return ` 35 |
  • 36 | ${cityName}, ${stateName} 37 | ${numberWithCommas(place.population)} 38 |
  • 39 | `; 40 | }) 41 | .join(""); 42 | suggestions.innerHTML = html; 43 | } 44 | 45 | const searchInput = document.querySelector(".search"); 46 | const suggestions = document.querySelector(".suggestions"); 47 | 48 | searchInput.addEventListener("change", displayMatches); 49 | searchInput.addEventListener("keyup", displayMatches); 50 | -------------------------------------------------------------------------------- /06-Type-Ahead/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | background-image: url('../../assets/special-delivery.jpg'); 4 | background-color: #D8C547; 5 | font-family: "helvetica neue"; 6 | font-size: 20px; 7 | font-weight: 200; 8 | } 9 | 10 | *, 11 | *:before, 12 | *:after { 13 | box-sizing: inherit; 14 | } 15 | 16 | input { 17 | width: 100%; 18 | padding: 20px; 19 | } 20 | 21 | .search-form { 22 | max-width: 400px; 23 | margin: 50px auto; 24 | } 25 | 26 | input.search { 27 | margin: 0; 28 | text-align: center; 29 | outline: 0; 30 | border: 10px solid #f7f7f7; 31 | width: 120%; 32 | left: -10%; 33 | position: relative; 34 | top: 10px; 35 | z-index: 2; 36 | border-radius: 5px; 37 | font-size: 40px; 38 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.19); 39 | } 40 | 41 | .suggestions { 42 | margin: 0; 43 | padding: 0; 44 | position: relative; 45 | /*perspective: 20px;*/ 46 | } 47 | 48 | .suggestions li { 49 | background: white; 50 | list-style: none; 51 | border-bottom: 1px solid #d8d8d8; 52 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.14); 53 | margin: 0; 54 | padding: 20px; 55 | transition: background 0.2s; 56 | display: flex; 57 | justify-content: space-between; 58 | text-transform: capitalize; 59 | } 60 | 61 | .suggestions li:nth-child(even) { 62 | transform: perspective(100px) rotateX(3deg) translateY(2px) scale(1.001); 63 | background: linear-gradient(to bottom, #ffffff 0%, #efefef 100%); 64 | } 65 | 66 | .suggestions li:nth-child(odd) { 67 | transform: perspective(100px) rotateX(-3deg) translateY(3px); 68 | background: linear-gradient(to top, #ffffff 0%, #efefef 100%); 69 | } 70 | 71 | span.population { 72 | font-size: 15px; 73 | } 74 | 75 | .hl { 76 | background: #ffc600; 77 | } 78 | -------------------------------------------------------------------------------- /07-Array-Cardio-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Array Cardio 💪💪 - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
    30 |
    #7
    31 |
    of JavaScript30
    32 |
    33 |
    34 |

    Psst: have a look at the JavaScript Console 💁

    35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /07-Array-Cardio-2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "array-cardio-2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /07-Array-Cardio-2/src/index.js: -------------------------------------------------------------------------------- 1 | // ## Array Cardio Day 2 2 | const people = [ 3 | { name: "Wes", year: 1988 }, 4 | { name: "Kait", year: 1986 }, 5 | { name: "Irv", year: 1970 }, 6 | { name: "Lux", year: 2015 } 7 | ]; 8 | const comments = [ 9 | { text: "Love this!", id: 523423 }, 10 | { text: "Super good", id: 823423 }, 11 | { text: "You are the best", id: 2039842 }, 12 | { text: "Ramen is my fav food ever", id: 123523 }, 13 | { text: "Nice Nice Nice!", id: 542328 } 14 | ]; 15 | // Some and Every Checks 16 | // Array.prototype.some() // is at least one person 19 or older? 17 | const isAdult = people.some( 18 | person => new Date().getFullYear() - person.year >= 19 19 | ); 20 | console.log({ isAdult }); 21 | 22 | // Array.prototype.every() // is everyone 19 or older? 23 | const allAdults = people.every( 24 | person => new Date().getFullYear() - person.year >= 19 25 | ); 26 | console.log({ allAdults }); 27 | 28 | // Array.prototype.find() 29 | // Find is like filter, but instead returns just the one you are looking for 30 | // find the comment with the ID of 823423 31 | const comment = comments.find(comment => comment.id === 823423); 32 | console.log(comment); 33 | 34 | // Array.prototype.findIndex() 35 | // Find the comment with this ID 36 | const index = comments.findIndex(comment => comment.id === 823423); 37 | 38 | // delete the comment with the ID of 823423 39 | 40 | // comments.splice(index, 1); 41 | // console.table(comments); 42 | 43 | const newComments = [...comments.slice(0, index), ...comments.slice(index + 1)]; 44 | console.table(newComments); 45 | -------------------------------------------------------------------------------- /07-Array-Cardio-2/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('../../assets/green-goblin.png'); 3 | background-color: #8AAA00; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | height: 100vh; 8 | font-family: monospace; 9 | font-size: large; 10 | font-weight: bolder; 11 | } -------------------------------------------------------------------------------- /08-HTML5-Canvas/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML5 Canvas - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
    30 |
    #8
    31 |
    of JavaScript30
    32 |
    33 |
    34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /08-HTML5-Canvas/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html5-canvas", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /08-HTML5-Canvas/src/index.js: -------------------------------------------------------------------------------- 1 | const canvas = document.querySelector("#draw"); 2 | const context = canvas.getContext("2d"); 3 | canvas.width = window.innerWidth; 4 | canvas.height = window.innerHeight; 5 | context.font = "8px"; 6 | context.fillText("Start Painting", window.innerWidth / 2, 50); 7 | context.strokeStyle = "#BADA55"; 8 | context.lineJoin = "round"; 9 | context.lineCap = "round"; 10 | context.lineWidth = 0; 11 | context.globalCompositeOperation = "lighten"; 12 | 13 | let isDrawing = false; 14 | let lastX = 0; 15 | let lastY = 0; 16 | let hue = 0; 17 | let direction = true; 18 | function draw(e) { 19 | //stop fxn from running when not mouse downed 20 | if (!isDrawing) return; 21 | // console.log(e); 22 | context.strokeStyle = `hsl(${hue++}, 100%, 50%)`; 23 | context.beginPath(); 24 | //start from 25 | context.moveTo(lastX, lastY); 26 | //go to 27 | context.lineTo(e.offsetX, e.offsetY); 28 | context.stroke(); 29 | [lastX, lastY] = [e.offsetX, e.offsetY]; 30 | 31 | if (hue >= 360) { 32 | hue = 0; 33 | } 34 | if (context.lineWidth >= 100 || context.lineWidth <= 1) { 35 | direction = !direction; 36 | } 37 | if (direction) { 38 | context.lineWidth++; 39 | } else { 40 | context.lineWidth--; 41 | } 42 | } 43 | 44 | canvas.addEventListener("mousemove", draw); 45 | canvas.addEventListener("mousedown", e => { 46 | isDrawing = true; 47 | [lastX, lastY] = [e.offsetX, e.offsetY]; 48 | }); 49 | canvas.addEventListener("mouseup", () => (isDrawing = false)); 50 | canvas.addEventListener("mouseout", () => (isDrawing = false)); 51 | // canvas.addEventListener("mouseover", () => (isDrawing = true)); 52 | -------------------------------------------------------------------------------- /08-HTML5-Canvas/src/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | } 5 | -------------------------------------------------------------------------------- /09-Dev-Tools/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dev Tools - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
    30 |
    #9
    31 |
    of JavaScript30
    32 |
    33 |
    34 |

    × DON'T×CLICK ×

    35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /09-Dev-Tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devtools-tricks", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /09-Dev-Tools/src/index.js: -------------------------------------------------------------------------------- 1 | const dogs = [{ name: 'Snickers', age: 2 }, { name: 'hugo', age: 8 }]; 2 | 3 | function makeGreen() { 4 | const p = document.querySelector('p'); 5 | p.style.color = '#BADA55'; 6 | p.style.fontSize = '50px'; 7 | p.innerText = "x GO, HAVE A LOOK AT CONSOLE x" 8 | } 9 | 10 | // Regular 11 | console.log("hello"); 12 | // Interpolated 13 | console.log("Hello I am a %s string!", "💩"); 14 | // Styled 15 | console.log('%c I am some great text', 'font-size:50px; background:red; text-shadow: 10px 10px 0 blue') 16 | // warning! 17 | console.warn("OH NOOO"); 18 | // Error :| 19 | console.error("Shit!"); 20 | // Info 21 | console.info("Crocodiles eat 3-4 people per year"); 22 | // Testing 23 | const p = document.querySelector("p"); 24 | console.assert(p.classList.contains("ouch"), "That is wrong!"); 25 | // clearing 26 | console.clear(); 27 | // Viewing DOM Elements 28 | console.log(p); 29 | console.dir(p); 30 | console.clear(); 31 | // Grouping together 32 | dogs.forEach(dog => { 33 | console.groupCollapsed(`${dog.name}`); 34 | console.log(`This is ${dog.name}`); 35 | console.log(`${dog.name} is ${dog.age} years old`); 36 | console.log(`${dog.name} is ${dog.age * 7} dog years old`); 37 | console.groupEnd(`${dog.name}`); 38 | }); 39 | // counting 40 | console.count("Ayush"); 41 | console.count("Ayush"); 42 | console.count("Gupta"); 43 | console.count("Gupta"); 44 | console.count("Ayush"); 45 | console.count("Gupta"); 46 | console.count("Ayush"); 47 | console.count("Gupta"); 48 | console.count("Gupta"); 49 | console.count("Gupta"); 50 | console.count("Gupta"); 51 | console.count("Gupta"); 52 | // timing 53 | console.time("fetching data"); 54 | fetch("https://api.github.com/users/gupta-ji6") 55 | .then(data => data.json()) 56 | .then(data => { 57 | console.timeEnd("fetching data"); 58 | console.log(data); 59 | }); 60 | console.table(dogs); 61 | -------------------------------------------------------------------------------- /10-Multiple-Check-Shift/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hold Shift to Check Multiple Checkboxes - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 31 | 32 |
    33 |
    #10
    34 |
    of JavaScript30
    35 |
    36 |
    37 |
    38 |
    39 | 40 |

    This is an inbox layout.

    41 |
    42 |
    43 | 44 |

    Check one item

    45 |
    46 |
    47 | 48 |

    Hold down your Shift key

    49 |
    50 |
    51 | 52 |

    Check a lower item

    53 |
    54 |
    55 | 56 |

    Everything in between should also be set to checked

    57 |
    58 |
    59 | 60 |

    Try to do it without any libraries

    61 |
    62 |
    63 | 64 |

    Just regular JavaScript

    65 |
    66 |
    67 | 68 |

    Good Luck!

    69 |
    70 |
    71 | 72 |

    Don't forget to tweet your result!

    73 |
    74 |
    75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /10-Multiple-Check-Shift/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multiple-check-with-shift", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /10-Multiple-Check-Shift/src/index.js: -------------------------------------------------------------------------------- 1 | const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]'); 2 | 3 | let lastChecked; 4 | 5 | function handleCheck(e) { 6 | // check if they had shiift key down and they are checking it, not unchecking it 7 | let inBetween = false; 8 | if (e.shiftKey && this.checked) { 9 | // loop over every single checkbox 10 | checkboxes.forEach(checkbox => { 11 | if (checkbox === this || checkbox === lastChecked) { 12 | inBetween = !inBetween; 13 | } 14 | 15 | if (inBetween) { 16 | checkbox.checked = true; 17 | } 18 | }); 19 | } 20 | lastChecked = this; 21 | } 22 | 23 | checkboxes.forEach(checkbox => checkbox.addEventListener("click", handleCheck)); 24 | -------------------------------------------------------------------------------- /10-Multiple-Check-Shift/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | background: #CBDEE6; 4 | background-image: url('../../assets/plaid.jpg'); 5 | } 6 | .inbox { 7 | max-width: 400px; 8 | margin: 50px auto; 9 | background: white; 10 | border-radius: 5px; 11 | box-shadow: 10px 10px 0 rgba(0,0,0,0.1); 12 | } 13 | .item { 14 | display: flex; 15 | align-items: center; 16 | border-bottom: 1px solid #F1F1F1; 17 | } 18 | .item:last-child { 19 | border-bottom: 0; 20 | } 21 | input:checked + p { 22 | background: #F9F9F9; 23 | text-decoration: line-through; 24 | } 25 | input[type="checkbox"] { 26 | margin: 20px; 27 | } 28 | p { 29 | margin: 0; 30 | padding: 20px; 31 | transition: background 0.2s; 32 | flex: 1; 33 | font-family:'helvetica neue'; 34 | font-size: 20px; 35 | font-weight: 200; 36 | border-left: 1px solid #D1E2FF; 37 | } -------------------------------------------------------------------------------- /11-Custom-Video-Player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML Video Player - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #11
    30 |
    of JavaScript30
    31 |
    32 |
    33 |
    34 | 38 | 39 |
    40 |
    41 |
    42 |
    43 | 44 | 53 | 62 | 63 | 64 | 65 |
    66 |
    67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /11-Custom-Video-Player/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-htm5-player", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /11-Custom-Video-Player/src/index.js: -------------------------------------------------------------------------------- 1 | // Get elements 2 | const player = document.querySelector(".player"); 3 | const video = player.querySelector(".viewer"); 4 | const progress = player.querySelector(".progress"); 5 | const progressBar = player.querySelector(".progress__filled"); 6 | const toggle = player.querySelector(".toggle"); 7 | const skipButtons = player.querySelectorAll("[data-skip]"); 8 | const ranges = player.querySelectorAll(".player__slider"); 9 | const fullScreen = player.querySelector(".player__fullscreen"); 10 | 11 | // Build Functions 12 | function togglePlay() { 13 | const method = video.paused ? "play" : "pause"; 14 | video[method](); 15 | // if(video.paused) { 16 | // video.play(); 17 | // } else { 18 | // video.pause(); 19 | // } 20 | } 21 | 22 | function updateButton() { 23 | const icon = this.paused ? "►" : "Pause"; 24 | toggle.textContent = icon; 25 | } 26 | 27 | function skip() { 28 | video.currentTime += parseFloat(this.dataset.skip); 29 | } 30 | 31 | function handleRangeChange() { 32 | video[this.name] = this.value; 33 | console.log(this.value); 34 | console.log(this.name); 35 | } 36 | 37 | function handleProgress() { 38 | const percent = (video.currentTime / video.duration) * 100; 39 | progressBar.style.flexBasis = `${percent}%`; 40 | } 41 | 42 | function scrub(e) { 43 | const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration; 44 | video.currentTime = scrubTime; 45 | } 46 | 47 | function handleFullscreen() { 48 | if (!isFull) { 49 | fullScreen.textContent = "Exit Fullscreen"; 50 | if (player.requestFullscreen) { 51 | player.requestFullscreen(); 52 | } else if (player.mozRequestFullScreen) { 53 | /* Firefox */ 54 | player.mozRequestFullScreen(); 55 | } else if (player.webkitRequestFullscreen) { 56 | /* Chrome, Safari and Opera */ 57 | player.webkitRequestFullscreen(); 58 | } else if (player.msRequestFullscreen) { 59 | /* IE/Edge */ 60 | player.msRequestFullscreen(); 61 | } 62 | } else if (isFull) { 63 | fullScreen.textContent = "Fullscreen"; 64 | 65 | if (document.exitFullscreen) { 66 | document.exitFullscreen(); 67 | } else if (document.webkitCancelFullScreen) { 68 | document.webkitCancelFullScreen(); 69 | } else if (player.mozCancelFullScreen) { 70 | player.mozCancelFullScreen(); 71 | } else if (player.msCancelFullScreen) { 72 | player.msCancelFullScreen(); 73 | } 74 | } 75 | isFull = !isFull; 76 | } 77 | 78 | // Add evenet listeners 79 | video.addEventListener("click", togglePlay); 80 | video.addEventListener("play", updateButton); 81 | video.addEventListener("pause", updateButton); 82 | video.addEventListener("timeupdate", handleProgress); 83 | toggle.addEventListener("click", togglePlay); 84 | 85 | skipButtons.forEach(button => button.addEventListener("click", skip)); 86 | 87 | ranges.forEach(range => range.addEventListener("change", handleRangeChange)); 88 | 89 | let mousedown = false; 90 | progress.addEventListener("click", scrub); 91 | progress.addEventListener("mousemove", e => mousedown && scrub(e)); 92 | progress.addEventListener("mousedown", () => (mousedown = true)); 93 | progress.addEventListener("mouseup", () => (mousedown = false)); 94 | let isFull = false; 95 | fullScreen.addEventListener("click", handleFullscreen); 96 | -------------------------------------------------------------------------------- /11-Custom-Video-Player/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, 6 | *:before, 7 | *:after { 8 | box-sizing: inherit; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | padding: 0; 14 | display: flex; 15 | background: #7a419b; 16 | min-height: 100vh; 17 | /* background: linear-gradient(135deg, #7c1599 0%, #921099 48%, #7e4ae8 100%); */ 18 | background-color: #9B39A8; 19 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56 28' width='56' height='28'%3E%3Cpath fill='%23ebeaec' fill-opacity='0.18' d='M56 26v2h-7.75c2.3-1.27 4.94-2 7.75-2zm-26 2a2 2 0 1 0-4 0h-4.09A25.98 25.98 0 0 0 0 16v-2c.67 0 1.34.02 2 .07V14a2 2 0 0 0-2-2v-2a4 4 0 0 1 3.98 3.6 28.09 28.09 0 0 1 2.8-3.86A8 8 0 0 0 0 6V4a9.99 9.99 0 0 1 8.17 4.23c.94-.95 1.96-1.83 3.03-2.63A13.98 13.98 0 0 0 0 0h7.75c2 1.1 3.73 2.63 5.1 4.45 1.12-.72 2.3-1.37 3.53-1.93A20.1 20.1 0 0 0 14.28 0h2.7c.45.56.88 1.14 1.29 1.74 1.3-.48 2.63-.87 4-1.15-.11-.2-.23-.4-.36-.59H26v.07a28.4 28.4 0 0 1 4 0V0h4.09l-.37.59c1.38.28 2.72.67 4.01 1.15.4-.6.84-1.18 1.3-1.74h2.69a20.1 20.1 0 0 0-2.1 2.52c1.23.56 2.41 1.2 3.54 1.93A16.08 16.08 0 0 1 48.25 0H56c-4.58 0-8.65 2.2-11.2 5.6 1.07.8 2.09 1.68 3.03 2.63A9.99 9.99 0 0 1 56 4v2a8 8 0 0 0-6.77 3.74c1.03 1.2 1.97 2.5 2.79 3.86A4 4 0 0 1 56 10v2a2 2 0 0 0-2 2.07 28.4 28.4 0 0 1 2-.07v2c-9.2 0-17.3 4.78-21.91 12H30zM7.75 28H0v-2c2.81 0 5.46.73 7.75 2zM56 20v2c-5.6 0-10.65 2.3-14.28 6h-2.7c4.04-4.89 10.15-8 16.98-8zm-39.03 8h-2.69C10.65 24.3 5.6 22 0 22v-2c6.83 0 12.94 3.11 16.97 8zm15.01-.4a28.09 28.09 0 0 1 2.8-3.86 8 8 0 0 0-13.55 0c1.03 1.2 1.97 2.5 2.79 3.86a4 4 0 0 1 7.96 0zm14.29-11.86c1.3-.48 2.63-.87 4-1.15a25.99 25.99 0 0 0-44.55 0c1.38.28 2.72.67 4.01 1.15a21.98 21.98 0 0 1 36.54 0zm-5.43 2.71c1.13-.72 2.3-1.37 3.54-1.93a19.98 19.98 0 0 0-32.76 0c1.23.56 2.41 1.2 3.54 1.93a15.98 15.98 0 0 1 25.68 0zm-4.67 3.78c.94-.95 1.96-1.83 3.03-2.63a13.98 13.98 0 0 0-22.4 0c1.07.8 2.09 1.68 3.03 2.63a9.99 9.99 0 0 1 16.34 0z'%3E%3C/path%3E%3C/svg%3E"); 20 | align-items: center; 21 | justify-content: center; 22 | } 23 | 24 | .player { 25 | max-width: 750px; 26 | border: 5px solid rgba(0, 0, 0, 0.2); 27 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); 28 | position: relative; 29 | font-size: 0; 30 | overflow: hidden; 31 | } 32 | 33 | /* This css is only applied when fullscreen is active. */ 34 | .player:fullscreen { 35 | max-width: none; 36 | width: 100%; 37 | } 38 | 39 | .player:-webkit-full-screen { 40 | max-width: none; 41 | width: 100%; 42 | } 43 | 44 | .player__video { 45 | width: 100%; 46 | } 47 | 48 | .player__button { 49 | background: none; 50 | border: 0; 51 | line-height: 1; 52 | color: white; 53 | text-align: center; 54 | outline: 0; 55 | padding: 0; 56 | cursor: pointer; 57 | max-width: 50px; 58 | } 59 | 60 | .player__button:focus { 61 | border-color: #9B39A8; 62 | } 63 | 64 | .player__slider { 65 | width: 10px; 66 | height: 30px; 67 | } 68 | 69 | .player__controls { 70 | display: flex; 71 | position: absolute; 72 | bottom: 0; 73 | width: 100%; 74 | transform: translateY(100%) translateY(-5px); 75 | transition: all 0.3s; 76 | flex-wrap: wrap; 77 | background: rgba(0, 0, 0, 0.1); 78 | } 79 | 80 | .player:hover .player__controls { 81 | transform: translateY(0); 82 | } 83 | 84 | .player:hover .progress { 85 | height: 15px; 86 | } 87 | 88 | .player__controls > * { 89 | flex: 1; 90 | } 91 | 92 | .progress { 93 | flex: 10; 94 | position: relative; 95 | display: flex; 96 | flex-basis: 100%; 97 | height: 5px; 98 | transition: height 0.3s; 99 | background: rgba(0, 0, 0, 0.5); 100 | cursor: ew-resize; 101 | } 102 | 103 | .progress__filled { 104 | width: 50%; 105 | background: #9B39A8; 106 | flex: 0; 107 | flex-basis: 50%; 108 | } 109 | 110 | /* unholy css to style input type="range" */ 111 | 112 | input[type='range'] { 113 | -webkit-appearance: none; 114 | background: transparent; 115 | width: 100%; 116 | margin: 0 5px; 117 | } 118 | 119 | input[type='range']:focus { 120 | outline: none; 121 | } 122 | 123 | input[type='range']::-webkit-slider-runnable-track { 124 | width: 100%; 125 | height: 8.4px; 126 | cursor: pointer; 127 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); 128 | background: rgba(255, 255, 255, 0.8); 129 | border-radius: 1.3px; 130 | border: 0.2px solid rgba(1, 1, 1, 0); 131 | } 132 | 133 | input[type='range']::-webkit-slider-thumb { 134 | height: 15px; 135 | width: 15px; 136 | border-radius: 50px; 137 | background: #9B39A8; 138 | cursor: pointer; 139 | -webkit-appearance: none; 140 | margin-top: -3.5px; 141 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.2); 142 | } 143 | 144 | input[type='range']:focus::-webkit-slider-runnable-track { 145 | background: #bada55; 146 | } 147 | 148 | input[type='range']::-moz-range-track { 149 | width: 100%; 150 | height: 8.4px; 151 | cursor: pointer; 152 | box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); 153 | background: #ffffff; 154 | border-radius: 1.3px; 155 | border: 0.2px solid rgba(1, 1, 1, 0); 156 | } 157 | 158 | input[type='range']::-moz-range-thumb { 159 | box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); 160 | height: 15px; 161 | width: 15px; 162 | border-radius: 50px; 163 | background: #9B39A8; 164 | cursor: pointer; 165 | } 166 | -------------------------------------------------------------------------------- /12-Key-Sequence-Detection/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Key Detection - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #12
    30 |
    of JavaScript30
    31 |
    32 |
    33 |
    34 |

    🎊 Type my nickname for a surprise! 🎊

    35 |
    36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /12-Key-Sequence-Detection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "key-sequence-detection", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": { 11 | "confetti-js": "0.0.16" 12 | }, 13 | "devDependencies": { 14 | "@babel/core": "7.2.0", 15 | "parcel-bundler": "^1.6.1" 16 | }, 17 | "keywords": [] 18 | } 19 | -------------------------------------------------------------------------------- /12-Key-Sequence-Detection/src/index.js: -------------------------------------------------------------------------------- 1 | // import ConfettiGenerator from "confetti-js"; 2 | const pressed = []; 3 | const secretCode = "guptaji"; 4 | console.info(`Hint: Type ${secretCode} on your keyboard`); 5 | let confettiSettings = { target: "my-canvas", animate: true,size: 4, clock: 100 }; 6 | 7 | window.addEventListener("keyup", e => { 8 | pressed.push(e.key); 9 | pressed.splice(-secretCode.length - 1, pressed.length - secretCode.length); 10 | console.log(pressed); 11 | if (pressed.join("").includes(secretCode)) { 12 | var confetti = new ConfettiGenerator(confettiSettings); 13 | confetti.render(); 14 | } else { 15 | var confettii = new ConfettiGenerator(confettiSettings); 16 | confettii.clear(); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /12-Key-Sequence-Detection/src/styles.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | background-image: url('../../assets/ocean.jpg'); 4 | background-color: #1e1e1e; 5 | height: 100vh; 6 | } 7 | 8 | .title { 9 | position: absolute; 10 | width: 60vw;; 11 | left: 20vw; 12 | right: 20vw; 13 | margin-top: 10vh; 14 | color: white; 15 | font-family: monospace; 16 | text-align: center; 17 | } 18 | -------------------------------------------------------------------------------- /13-Slide-In-On-Scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slide-in-on-scroll", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /13-Slide-In-On-Scroll/src/index.js: -------------------------------------------------------------------------------- 1 | function debounce(func, wait = 20, immediate = true) { 2 | var timeout; 3 | return function() { 4 | var context = this, 5 | args = arguments; 6 | var later = function() { 7 | timeout = null; 8 | if (!immediate) func.apply(context, args); 9 | }; 10 | var callNow = immediate && !timeout; 11 | clearTimeout(timeout); 12 | timeout = setTimeout(later, wait); 13 | if (callNow) func.apply(context, args); 14 | }; 15 | } 16 | 17 | const sliderImages = document.querySelectorAll(".slide-in"); 18 | 19 | function checkSlide(e) { 20 | sliderImages.forEach(sliderImage => { 21 | //half way through the image 22 | const slideInAt = 23 | window.scrollY + window.innerHeight - sliderImage.height / 2; 24 | // bottom of the image for when you scroll up 25 | const imageBottom = sliderImage.offsetTop + sliderImage.height; 26 | const isHalfShown = slideInAt > sliderImage.offsetTop; 27 | const isNotScrollPast = window.scrollY < imageBottom; 28 | if (isHalfShown && isNotScrollPast) { 29 | sliderImage.classList.add("active"); 30 | } else { 31 | sliderImage.classList.remove("active"); 32 | } 33 | }); 34 | } 35 | 36 | window.addEventListener("scroll", debounce(checkSlide)); 37 | -------------------------------------------------------------------------------- /13-Slide-In-On-Scroll/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | background-color: #2a7966; 4 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.2'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 5 | font-family: 'helvetica neue'; 6 | font-size: 20px; 7 | font-weight: 200; 8 | } 9 | 10 | body { 11 | margin: 0; 12 | } 13 | 14 | *, 15 | *:before, 16 | *:after { 17 | box-sizing: inherit; 18 | } 19 | h1 { 20 | margin-top: 0; 21 | } 22 | .site-wrap { 23 | max-width: 700px; 24 | margin: 100px auto; 25 | background: white; 26 | padding: 40px; 27 | text-align: justify; 28 | } 29 | .align-left { 30 | float: left; 31 | margin-right: 20px; 32 | } 33 | .align-right { 34 | float: right; 35 | margin-left: 20px; 36 | } 37 | .slide-in { 38 | opacity: 0; 39 | transition: all 0.5s; 40 | } 41 | .align-left.slide-in { 42 | transform: translateX(-30%) scale(0.95); 43 | } 44 | 45 | .align-right.slide-in { 46 | transform: translateX(30%) scale(0.95); 47 | } 48 | .slide-in.active { 49 | opacity: 1; 50 | transform: translateX(0%) scale(1); 51 | } 52 | -------------------------------------------------------------------------------- /14-JS-Reference-Vs-Copy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JS Reference VS Copy - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
    30 |
    #14
    31 |
    of JavaScript30
    32 |
    33 |
    34 |

    Have a look at the source code for understanding reference vs copy in JS.

    35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /14-JS-Reference-Vs-Copy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-reference-vs-copy", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /14-JS-Reference-Vs-Copy/src/index.js: -------------------------------------------------------------------------------- 1 | // start with strings, numbers and booleans 2 | 3 | // let age = 100; 4 | // let age2 = age; 5 | // console.log(age, age2); 6 | 7 | // age = 200; 8 | // console.log(age, age2); 9 | 10 | // let name = 'Wes'; 11 | // let name2 = name; 12 | // console.log(name, name2); 13 | 14 | // name = 'wesley'; 15 | // console.log(name, name2); 16 | 17 | // Let's say we have an array 18 | 19 | const players = ["Wes", "Sarah", "Ryan", "Poppy"]; 20 | 21 | // and we want to make a copy of it. 22 | 23 | const team = players; 24 | console.log(players, team); 25 | 26 | // You might think we can just do something like this: 27 | 28 | // team[3] = 'Lux'; 29 | 30 | // however what happens when we update that array? 31 | // now here is the problem! 32 | // oh no - we have edited the original array too! 33 | // Why? It's because that is an array reference, not an array copy. They both point to the same array! 34 | // So, how do we fix this? We take a copy instead! 35 | 36 | const team2 = players.slice(); 37 | 38 | // one way 39 | // or create a new array and concat the old one in 40 | 41 | const team3 = [].concat(players); 42 | 43 | // or use the new ES6 Spread 44 | 45 | const team4 = [...players]; 46 | team4[3] = "heeee hawww"; 47 | 48 | console.log(team4); 49 | const team5 = Array.from(players); 50 | 51 | // now when we update it, the original one isn't changed 52 | // The same thing goes for objects, let's say we have a person object 53 | // with Objects 54 | 55 | const person = { 56 | name: "Wes Bos", 57 | age: 80 58 | }; 59 | 60 | // and think we make a copy: 61 | 62 | // const captain = person; 63 | // captain.number = 99; 64 | 65 | // how do we take a copy instead? 66 | 67 | const cap2 = Object.assign({}, person, { number: 99, age: 12 }); 68 | console.log(cap2); 69 | 70 | // We will hopefully soon see the object ...spread 71 | // const cap3 = {...person}; 72 | // Things to note - this is only 1 level deep - both for Arrays and Objects. lodash has a cloneDeep method, but you should think twice before using it. 73 | 74 | const ayush = { 75 | name: "Ayush", 76 | age: 23, 77 | social: { 78 | twitter: "@_guptaji_", 79 | facebook: "guptaji.6" 80 | } 81 | }; 82 | 83 | console.clear(); 84 | console.log(ayush); 85 | 86 | const dev = Object.assign({}, ayush); 87 | const dev2 = JSON.parse(JSON.stringify(ayush)); 88 | -------------------------------------------------------------------------------- /15-Localstorage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LocalStorage - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 32 | 33 | 34 |
    35 |
    #15
    36 |
    of JavaScript30
    37 |
    38 |
    39 | 40 | 50 | 51 | 54 | 57 | 60 | 63 | 66 | 67 | 68 | 69 | 70 |
    71 |

    LOCAL TAPAS

    72 |

    73 | 76 |
    77 | 78 | 79 |
    80 |
    81 | 82 | 83 |
    84 |
    85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /15-Localstorage/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "localstorage-event-deligation", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /15-Localstorage/src/index.js: -------------------------------------------------------------------------------- 1 | const addItems = document.querySelector(".add-items"); 2 | const itemsList = document.querySelector(".plates"); 3 | let items = JSON.parse(localStorage.getItem("items")) || []; 4 | const deleteBtn = document.querySelector(".delete"); 5 | const checkBtn = document.querySelector(".check-uncheck"); 6 | 7 | function addItem(e) { 8 | e.preventDefault(); 9 | const text = this.querySelector("[name = item]").value; 10 | const item = { 11 | text, 12 | done: false 13 | }; 14 | items.push(item); 15 | populateList(items, itemsList); 16 | localStorage.setItem("items", JSON.stringify(items)); 17 | this.reset(); 18 | } 19 | 20 | function populateList(plates = [], platesList) { 21 | platesList.innerHTML = plates 22 | .map((plate, i) => { 23 | return ` 24 |
  • 25 | 28 | 29 |
  • 30 | `; 31 | }) 32 | .join(""); 33 | } 34 | 35 | // event delegation is done here 36 | // instead of listening to clicks on
  • /itemsList, we're listening it on it's parent ul 37 | function toggleDone(e) { 38 | if (!e.target.matches("input")) return; //skip this if the item we're clicking is not input 39 | const el = e.target; 40 | const index = el.dataset.index; 41 | items[index].done = !items[index].done; 42 | localStorage.setItem("items", JSON.stringify(items)); 43 | populateList(items, itemsList); 44 | } 45 | 46 | function deleteAll() { 47 | if (window.confirm("Are you sure you want to delete all items?")) { 48 | itemsList.innerHTML = `
  • Loading Tapas...
  • `; 49 | items = []; 50 | localStorage.removeItem("items"); 51 | } 52 | } 53 | 54 | let isChecked = false; 55 | function checkOrUncheckAll() { 56 | if (!isChecked) { 57 | items.map(item => { 58 | return (item.done = true); 59 | }); 60 | populateList(items, itemsList); 61 | checkBtn.textContent = "Uncheck All"; 62 | } else { 63 | items.map(item => { 64 | return (item.done = false); 65 | }); 66 | populateList(items, itemsList); 67 | checkBtn.textContent = "Check All"; 68 | } 69 | isChecked = !isChecked; 70 | } 71 | 72 | addItems.addEventListener("submit", addItem); 73 | itemsList.addEventListener("click", toggleDone); 74 | deleteBtn.addEventListener("click", deleteAll); 75 | checkBtn.addEventListener("click", checkOrUncheckAll); 76 | 77 | populateList(items, itemsList); 78 | -------------------------------------------------------------------------------- /15-Localstorage/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | background-color: #184d47; 4 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 80' width='80' height='80'%3E%3Cpath fill='%2396bb7c' fill-opacity='0.16' d='M14 16H9v-2h5V9.87a4 4 0 1 1 2 0V14h5v2h-5v15.95A10 10 0 0 0 23.66 27l-3.46-2 8.2-2.2-2.9 5a12 12 0 0 1-21 0l-2.89-5 8.2 2.2-3.47 2A10 10 0 0 0 14 31.95V16zm40 40h-5v-2h5v-4.13a4 4 0 1 1 2 0V54h5v2h-5v15.95A10 10 0 0 0 63.66 67l-3.47-2 8.2-2.2-2.88 5a12 12 0 0 1-21.02 0l-2.88-5 8.2 2.2-3.47 2A10 10 0 0 0 54 71.95V56zm-39 6a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm40-40a2 2 0 1 1 0-4 2 2 0 0 1 0 4zM15 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm40 40a2 2 0 1 0 0-4 2 2 0 0 0 0 4z'%3E%3C/path%3E%3C/svg%3E"); 5 | min-height: 100vh; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | text-align: center; 10 | font-family: Futura, "Trebuchet MS", Arial, sans-serif; 11 | } 12 | 13 | *, 14 | *:before, 15 | *:after { 16 | box-sizing: inherit; 17 | } 18 | 19 | svg { 20 | fill: #eebb4d; 21 | background: rgba(0, 0, 0, 0.1); 22 | padding: 20px; 23 | border-radius: 50%; 24 | width: 200px; 25 | margin-bottom: 50px; 26 | } 27 | 28 | .wrapper { 29 | padding: 20px; 30 | max-width: 350px; 31 | background: rgba(255, 255, 255, 0.95); 32 | box-shadow: 0 0 0 10px #96bb7c; 33 | } 34 | 35 | h2 { 36 | text-align: center; 37 | margin: 0; 38 | font-weight: 200; 39 | } 40 | 41 | .plates { 42 | margin: 0; 43 | padding: 0; 44 | text-align: left; 45 | list-style: none; 46 | } 47 | 48 | .plates li { 49 | border-bottom: 1px solid rgba(0, 0, 0, 0.2); 50 | padding: 10px 0; 51 | font-weight: 100; 52 | display: flex; 53 | } 54 | 55 | .plates label { 56 | flex: 1; 57 | cursor: pointer; 58 | } 59 | 60 | .plates input { 61 | display: none; 62 | } 63 | 64 | .plates input + label:before { 65 | content: "⬜️"; 66 | margin-right: 10px; 67 | } 68 | 69 | .plates input:checked + label:before { 70 | content: "🌮"; 71 | } 72 | 73 | .add-items { 74 | margin-top: 20px; 75 | } 76 | 77 | .add-items input { 78 | padding: 10px; 79 | outline: 0; 80 | border: 1px solid rgba(0, 0, 0, 0.1); 81 | } 82 | 83 | .btn-group button { 84 | margin-top: 20px; 85 | padding: 10px; 86 | outline: 0; 87 | border: 1px solid rgba(0, 0, 0, 0.1); 88 | } 89 | 90 | .delete, .check-uncheck { 91 | background-color: #184d47; 92 | color: #d6efc7; 93 | } 94 | 95 | input[type="submit"] { 96 | background-color: #eebb4d; 97 | } 98 | 99 | input[type="text"] { 100 | border: 1px solid #96bb7c; 101 | } 102 | -------------------------------------------------------------------------------- /16-Mousemove-Shadow/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mouse Shadow - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #16
    30 |
    of JavaScript30
    31 |
    32 |
    33 |
    34 |

    🔥WOAH!

    35 | Pro Tip: The text above is editable ;-) 36 |
    37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /16-Mousemove-Shadow/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-mouse-move-effect", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /16-Mousemove-Shadow/src/index.js: -------------------------------------------------------------------------------- 1 | const hero = document.querySelector(".hero"); 2 | const text = hero.querySelector("h1"); 3 | const walk = 30; //100px 4 | 5 | function shadow(e) { 6 | const { offsetWidth: width, offsetHeight: height } = hero; 7 | let { offsetX: x, offsetY: y } = e; 8 | 9 | if (this !== e.target) { 10 | x += e.target.offsetLeft; 11 | y += e.target.offsetTop; 12 | } 13 | 14 | const xWalk = Math.round((x / width) * walk - walk / 2); 15 | const yWalk = Math.round((y / height) * walk - walk / 2); 16 | 17 | text.style.textShadow = ` 18 | ${xWalk}px ${yWalk}px 0 rgba(255, 0, 255, 0.7), 19 | ${xWalk * -1}px ${yWalk}px 0 rgba(0, 255, 255, 0.7), 20 | ${yWalk}px ${xWalk * -1}px 0 rgba(0, 255, 0, 0.7), 21 | ${yWalk * -1}px ${xWalk}px 0 rgba(0, 0, 255, 0.7) 22 | `; 23 | } 24 | 25 | hero.addEventListener("mousemove", shadow); 26 | -------------------------------------------------------------------------------- /16-Mousemove-Shadow/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | color: white; 3 | font-family: sans-serif; 4 | } 5 | body { 6 | margin: 0; 7 | background-image: url('../../assets/celebration.png'); 8 | } 9 | .hero { 10 | min-height: 100vh; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | flex-direction: column; 15 | color: white; 16 | } 17 | h1 { 18 | text-shadow: 10px 10px 0 rgba(0, 0, 0, 1); 19 | font-size: 100px; 20 | } 21 | 22 | h7{ 23 | color: lightcoral; 24 | font-family: monospace; 25 | } 26 | -------------------------------------------------------------------------------- /17-Sort-Without-Articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sort Without Articles - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #17
    30 |
    of JavaScript30
    31 |
    32 |
    33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /17-Sort-Without-Articles/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sort-without-articles", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [ 16 | "javascript30", 17 | "javascript" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /17-Sort-Without-Articles/src/index.js: -------------------------------------------------------------------------------- 1 | const bands = [ 2 | "The Plot in You", 3 | "The Devil Wears Prada", 4 | "Pierce the Veil", 5 | "Norma Jean", 6 | "The Bled", 7 | "Say Anything", 8 | "The Midway State", 9 | "We Came as Romans", 10 | "Counterparts", 11 | "Oh, Sleeper", 12 | "A Skylit Drive", 13 | "Anywhere But Here", 14 | "An Old Dog" 15 | ]; 16 | 17 | function strip(bandName) { 18 | return bandName.replace(/^(a |the |an )/i, "").trim(); 19 | } 20 | 21 | const sortBandsByAsc = bands.sort((a, b) => (strip(a) < strip(b) ? -1 : 1)); 22 | 23 | let bandsCopy = [...bands]; 24 | const sortBandsByDesc = bandsCopy.sort((a, b) => 25 | strip(a) > strip(b) ? -1 : 1 26 | ); 27 | 28 | const sortBtn = document.querySelector("#sort-btn"); 29 | let sortByAsc = true; 30 | 31 | document.querySelector("#bands").innerHTML = sortBandsByAsc 32 | .map(band => `
  • ${band}
  • `) 33 | .join(""); 34 | 35 | sortBtn.addEventListener("click", () => { 36 | sortByAsc = !sortByAsc; 37 | if (sortByAsc) { 38 | document.querySelector("#bands").innerHTML = sortBandsByAsc 39 | .map(band => `
  • ${band}
  • `) 40 | .join(""); 41 | sortBtn.textContent = "Sort by Descending"; 42 | } else { 43 | document.querySelector("#bands").innerHTML = sortBandsByDesc 44 | .map(band => `
  • ${band}
  • `) 45 | .join(""); 46 | sortBtn.textContent = "Sort by Ascending"; 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /17-Sort-Without-Articles/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: sans-serif; 4 | background: url('../../assets/asteroids.jpg'); 5 | display: flex; 6 | align-items: center; 7 | flex-direction: column; 8 | min-height: 100vh; 9 | padding: 30px; 10 | } 11 | 12 | #bands { 13 | list-style: inside square; 14 | font-size: 20px; 15 | background: #fb7813; 16 | width: 500px; 17 | margin: auto; 18 | padding: 0; 19 | box-shadow: 0 0 0 20px rgba(0, 0, 0, 0.05); 20 | } 21 | 22 | #bands li { 23 | border-bottom: 1px solid #efefef; 24 | padding: 20px; 25 | color: #f7f7ee; 26 | } 27 | 28 | #bands li:last-child { 29 | border-bottom: 0; 30 | } 31 | 32 | a { 33 | color: #ffc600; 34 | text-decoration: none; 35 | } 36 | -------------------------------------------------------------------------------- /18-Add-Time-With-Reduce/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Add Time With Reduce - JavaScript30 by Ayush Gupta 5 | 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 | 29 |
    30 |
    #18
    31 |
    of JavaScript30
    32 |
    33 |
    34 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /18-Add-Time-With-Reduce/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "add-time-reduce", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /18-Add-Time-With-Reduce/src/index.js: -------------------------------------------------------------------------------- 1 | const timeNodes = Array.from(document.querySelectorAll("[data-time]")); 2 | 3 | const seconds = timeNodes 4 | .map(node => node.dataset.time) 5 | .map(timeCode => { 6 | const [mins, secs] = timeCode.split(":").map(parseFloat); 7 | return mins * 60 + secs; 8 | }) 9 | .reduce((total, vidSeconds) => total + vidSeconds); 10 | 11 | let secondsLeft = seconds; 12 | const hours = Math.floor(secondsLeft / 3600); 13 | secondsLeft %= 3600; 14 | 15 | const mins = Math.floor(secondsLeft / 60); 16 | secondsLeft %= 60; 17 | 18 | console.log(hours, mins, secondsLeft); 19 | -------------------------------------------------------------------------------- /18-Add-Time-With-Reduce/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #2f2519; 3 | color: #fa7d09; 4 | font-family: sans-serif; 5 | display: flex; 6 | justify-content: center; 7 | } -------------------------------------------------------------------------------- /19-Webcam-Fun/.cache/57/730c4c4fbb17905544f6301244eb4f.json: -------------------------------------------------------------------------------- 1 | {"id":"index.html","dependencies":[{"name":"./src/styles.css","dynamic":true,"resolved":"/home/ayushgupta/Documents/JavaScript30/19-Webcam-Fun/src/styles.css","parent":"/home/ayushgupta/Documents/JavaScript30/19-Webcam-Fun/index.html"},{"name":"./src/index.js","dynamic":true,"resolved":"/home/ayushgupta/Documents/JavaScript30/19-Webcam-Fun/src/index.js","parent":"/home/ayushgupta/Documents/JavaScript30/19-Webcam-Fun/index.html"}],"generated":{"html":"\n\n \n \n Get User Media Code Along!\n \n \n \n
    \n
    \n \n
    \n \n \n \n \n
    \n \n \n \n \n
    \n \n \n \n \n
    \n
    \n\n \n \n
    \n
    \n\n \n\n \n \n\n"},"sourceMaps":null,"error":null,"hash":"0da55d9ca1167c4e022366da3e6eefcb","cacheData":{}} -------------------------------------------------------------------------------- /19-Webcam-Fun/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webcam Fun - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    #18
    17 |
    of JavaScript30
    18 |
    19 |
    20 |
    21 |

    PhotoBooth

    22 | 23 |
    24 |
    25 | 26 | 27 | 28 | 29 |
    30 | 31 | 32 | 33 | 34 |
    35 | 36 | 37 | 38 | 39 |
    40 |
    41 | 42 | 43 | 44 |
    45 | Click to download 46 |
    47 |
    48 |
    49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /19-Webcam-Fun/dist/src.a2b27638.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["src/index.js"],"names":["video","document","querySelector","canvas","ctx","getContext","strip","snap","getVideo","navigator","mediaDevices","getUserMedia","audio","then","localMediaStream","console","log","srcObject","play","catch","err","error","paintToCanvas","width","videoWidth","height","videoHeight","style","cssText","setInterval","drawImage","pixels","getImageData","rgbSplit","globalAlpha","putImageData","greenScreen","levels","querySelectorAll","forEach","input","name","value","i","data","length","red","green","blue","alpha","rmin","gmin","bmin","rmax","gmax","bmax","takePhoto","currentTime","toDataURL","link","createElement","href","setAttribute","innerHTML","insertBefore","firstChild","redEffect","addEventListener"],"mappings":"AAAA,IAAMA,KAAK,GAAGC,QAAQ,CAACC,aAAT,CAAuB,SAAvB,CAAd;AACA,IAAMC,MAAM,GAAGF,QAAQ,CAACC,aAAT,CAAuB,QAAvB,CAAf;AACA,IAAME,GAAG,GAAGD,MAAM,CAACE,UAAP,CAAkB,IAAlB,CAAZ;AACA,IAAMC,KAAK,GAAGL,QAAQ,CAACC,aAAT,CAAuB,QAAvB,CAAd;AACA,IAAMK,IAAI,GAAGN,QAAQ,CAACC,aAAT,CAAuB,OAAvB,CAAb;;AAEA,SAASM,QAAT,GAAoB;AAClBC,EAAAA,SAAS,CAACC,YAAV,CACGC,YADH,CACgB;AAAEX,IAAAA,KAAK,EAAE,IAAT;AAAeY,IAAAA,KAAK,EAAE;AAAtB,GADhB,EAEGC,IAFH,CAEQ,UAAAC,gBAAgB,EAAI;AACxBC,IAAAA,OAAO,CAACC,GAAR,CAAYF,gBAAZ;AACAd,IAAAA,KAAK,CAACiB,SAAN,GAAkBH,gBAAlB;AACAd,IAAAA,KAAK,CAACkB,IAAN;AACD,GANH,EAOGC,KAPH,CAOS,UAAAC,GAAG,EAAI;AACZL,IAAAA,OAAO,CAACM,KAAR,CAAc,aAAd,EAA6BD,GAA7B;AACD,GATH;AAUD;;AAED,SAASE,aAAT,GAAyB;AACvB,MAAMC,KAAK,GAAGvB,KAAK,CAACwB,UAApB;AACA,MAAMC,MAAM,GAAGzB,KAAK,CAAC0B,WAArB;AACA1B,EAAAA,KAAK,CAAC2B,KAAN,CAAYC,OAAZ,GACE;;wCADF;AAIAzB,EAAAA,MAAM,CAACoB,KAAP,GAAeA,KAAf;AACApB,EAAAA,MAAM,CAACsB,MAAP,GAAgBA,MAAhB;AAEA,SAAOI,WAAW,CAAC,YAAM;AACvBzB,IAAAA,GAAG,CAAC0B,SAAJ,CAAc9B,KAAd,EAAqB,CAArB,EAAwB,CAAxB,EAA2BuB,KAA3B,EAAkCE,MAAlC,EADuB,CAEvB;;AACA,QAAIM,MAAM,GAAG3B,GAAG,CAAC4B,YAAJ,CAAiB,CAAjB,EAAoB,CAApB,EAAuBT,KAAvB,EAA8BE,MAA9B,CAAb,CAHuB,CAIvB;AACA;;AAEAM,IAAAA,MAAM,GAAGE,QAAQ,CAACF,MAAD,CAAjB;AACA3B,IAAAA,GAAG,CAAC8B,WAAJ,GAAkB,GAAlB,CARuB,CAUvB;;AACA9B,IAAAA,GAAG,CAAC+B,YAAJ,CAAiBJ,MAAjB,EAAyB,CAAzB,EAA4B,CAA5B,EAXuB,CAYvB;AACD,GAbiB,EAaf,EAbe,CAAlB;AAcD;;AAED,SAASK,WAAT,CAAqBL,MAArB,EAA6B;AAC3B,MAAMM,MAAM,GAAG,EAAf;AAEApC,EAAAA,QAAQ,CAACqC,gBAAT,CAA0B,YAA1B,EAAwCC,OAAxC,CAAgD,UAAAC,KAAK,EAAI;AACvDH,IAAAA,MAAM,CAACG,KAAK,CAACC,IAAP,CAAN,GAAqBD,KAAK,CAACE,KAA3B;AACD,GAFD;;AAIA,OAAKC,CAAC,GAAG,CAAT,EAAYA,CAAC,GAAGZ,MAAM,CAACa,IAAP,CAAYC,MAA5B,EAAoCF,CAAC,GAAGA,CAAC,GAAG,CAA5C,EAA+C;AAC7CG,IAAAA,GAAG,GAAGf,MAAM,CAACa,IAAP,CAAYD,CAAC,GAAG,CAAhB,CAAN;AACAI,IAAAA,KAAK,GAAGhB,MAAM,CAACa,IAAP,CAAYD,CAAC,GAAG,CAAhB,CAAR;AACAK,IAAAA,IAAI,GAAGjB,MAAM,CAACa,IAAP,CAAYD,CAAC,GAAG,CAAhB,CAAP;AACAM,IAAAA,KAAK,GAAGlB,MAAM,CAACa,IAAP,CAAYD,CAAC,GAAG,CAAhB,CAAR;;AAEA,QACEG,GAAG,IAAIT,MAAM,CAACa,IAAd,IACAH,KAAK,IAAIV,MAAM,CAACc,IADhB,IAEAH,IAAI,IAAIX,MAAM,CAACe,IAFf,IAGAN,GAAG,IAAIT,MAAM,CAACgB,IAHd,IAIAN,KAAK,IAAIV,MAAM,CAACiB,IAJhB,IAKAN,IAAI,IAAIX,MAAM,CAACkB,IANjB,EAOE;AACA;AACAxB,MAAAA,MAAM,CAACa,IAAP,CAAYD,CAAC,GAAG,CAAhB,IAAqB,CAArB;AACD;AACF;;AAED,SAAOZ,MAAP;AACD;;AAED,SAASyB,SAAT,GAAqB;AACnB;AACAjD,EAAAA,IAAI,CAACkD,WAAL,GAAmB,CAAnB;AACAlD,EAAAA,IAAI,CAACW,IAAL;AAEA,MAAM0B,IAAI,GAAGzC,MAAM,CAACuD,SAAP,CAAiB,YAAjB,CAAb;AACA,MAAMC,IAAI,GAAG1D,QAAQ,CAAC2D,aAAT,CAAuB,GAAvB,CAAb;AACAD,EAAAA,IAAI,CAACE,IAAL,GAAYjB,IAAZ;AACAe,EAAAA,IAAI,CAACG,YAAL,CAAkB,UAAlB,EAA8B,UAA9B;AACAH,EAAAA,IAAI,CAACI,SAAL,wBAA8BnB,IAA9B;AACAtC,EAAAA,KAAK,CAAC0D,YAAN,CAAmBL,IAAnB,EAAyBrD,KAAK,CAAC2D,UAA/B;AACD;;AAED,SAASC,SAAT,CAAmBnC,MAAnB,EAA2B;AACzB,OAAK,IAAIY,EAAC,GAAG,CAAb,EAAgBA,EAAC,GAAGZ,MAAM,CAACa,IAAP,CAAYC,MAAhC,EAAwCF,EAAC,IAAI,CAA7C,EAAgD;AAC9CZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,EAAC,GAAG,CAAhB,KAAsB,GAAtB,CAD8C,CACnB;;AAC3BZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,EAAC,GAAG,CAAhB,KAAsB,EAAtB,CAF8C,CAEpB;;AAC1BZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,EAAC,GAAG,CAAhB,KAAsB,GAAtB,CAH8C,CAGnB;AAC5B;;AACD,SAAOZ,MAAP;AACD;;AAED,SAASE,QAAT,CAAkBF,MAAlB,EAA0B;AACxB,OAAK,IAAIY,GAAC,GAAG,CAAb,EAAgBA,GAAC,GAAGZ,MAAM,CAACa,IAAP,CAAYC,MAAhC,EAAwCF,GAAC,IAAI,CAA7C,EAAgD;AAC9CZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,GAAhB,IAAuBZ,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,CAAhB,CAAvB,CAD8C,CACH;;AAC3CZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,GAAhB,IAAuBZ,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,CAAhB,CAAvB,CAF8C,CAEH;;AAC3CZ,IAAAA,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,GAAhB,IAAuBZ,MAAM,CAACa,IAAP,CAAYD,GAAC,GAAG,CAAhB,CAAvB,CAH8C,CAGH;AAC5C;;AACD,SAAOZ,MAAP;AACD;;AAEDvB,QAAQ;AAERR,KAAK,CAACmE,gBAAN,CAAuB,SAAvB,EAAkC7C,aAAlC","file":"src.a2b27638.js","sourceRoot":"..","sourcesContent":["const video = document.querySelector(\".player\");\r\nconst canvas = document.querySelector(\".photo\");\r\nconst ctx = canvas.getContext(\"2d\");\r\nconst strip = document.querySelector(\".strip\");\r\nconst snap = document.querySelector(\".snap\");\r\n\r\nfunction getVideo() {\r\n navigator.mediaDevices\r\n .getUserMedia({ video: true, audio: false })\r\n .then(localMediaStream => {\r\n console.log(localMediaStream);\r\n video.srcObject = localMediaStream;\r\n video.play();\r\n })\r\n .catch(err => {\r\n console.error(\"Oh, NOOO!!!\", err);\r\n });\r\n}\r\n\r\nfunction paintToCanvas() {\r\n const width = video.videoWidth;\r\n const height = video.videoHeight;\r\n video.style.cssText =\r\n '-moz-transform: scale(-1, 1); \\\r\n-webkit-transform: scale(-1, 1); -o-transform: scale(-1, 1); \\\r\ntransform: scale(-1, 1); filter: FlipH;';\r\n canvas.width = width;\r\n canvas.height = height;\r\n\r\n return setInterval(() => {\r\n ctx.drawImage(video, 0, 0, width, height);\r\n // take pixels out\r\n let pixels = ctx.getImageData(0, 0, width, height);\r\n // mess with them\r\n // pixels = redEffect(pixels);\r\n\r\n pixels = rgbSplit(pixels);\r\n ctx.globalAlpha = 0.8;\r\n\r\n // put them back\r\n ctx.putImageData(pixels, 0, 0);\r\n // debugger;\r\n }, 16);\r\n}\r\n\r\nfunction greenScreen(pixels) {\r\n const levels = {};\r\n\r\n document.querySelectorAll(\".rgb input\").forEach(input => {\r\n levels[input.name] = input.value;\r\n });\r\n\r\n for (i = 0; i < pixels.data.length; i = i + 4) {\r\n red = pixels.data[i + 0];\r\n green = pixels.data[i + 1];\r\n blue = pixels.data[i + 2];\r\n alpha = pixels.data[i + 3];\r\n\r\n if (\r\n red >= levels.rmin &&\r\n green >= levels.gmin &&\r\n blue >= levels.bmin &&\r\n red <= levels.rmax &&\r\n green <= levels.gmax &&\r\n blue <= levels.bmax\r\n ) {\r\n // take it out!\r\n pixels.data[i + 3] = 0;\r\n }\r\n }\r\n\r\n return pixels;\r\n}\r\n\r\nfunction takePhoto() {\r\n // play sound\r\n snap.currentTime = 0;\r\n snap.play();\r\n\r\n const data = canvas.toDataURL(\"image/jpeg\");\r\n const link = document.createElement(\"a\");\r\n link.href = data;\r\n link.setAttribute(\"download\", \"handsome\");\r\n link.innerHTML = `Smart Man`;\r\n strip.insertBefore(link, strip.firstChild);\r\n}\r\n\r\nfunction redEffect(pixels) {\r\n for (let i = 0; i < pixels.data.length; i += 4) {\r\n pixels.data[i + 0] += 100; //r\r\n pixels.data[i + 1] -= 50; //g\r\n pixels.data[i + 2] *= 0.5; //b\r\n }\r\n return pixels;\r\n}\r\n\r\nfunction rgbSplit(pixels) {\r\n for (let i = 0; i < pixels.data.length; i += 4) {\r\n pixels.data[i - 150] = pixels.data[i + 0]; // RED\r\n pixels.data[i + 500] = pixels.data[i + 1]; // GREEN\r\n pixels.data[i - 550] = pixels.data[i + 2]; // Blue\r\n }\r\n return pixels;\r\n}\r\n\r\ngetVideo();\r\n\r\nvideo.addEventListener(\"canplay\", paintToCanvas);\r\n"]} -------------------------------------------------------------------------------- /19-Webcam-Fun/dist/styles.dd855970.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 10px; 4 | background-color: #f46036; 5 | background-image: url("data:image/svg+xml,%3Csvg width='80' height='80' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%232e294e' fill-opacity='0.2'%3E%3Cpath d='M50 50c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10zM10 10c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10S0 25.523 0 20s4.477-10 10-10zm10 8c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm40 40c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8z' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 6 | padding: 2vw; 7 | font-family: Arial, Helvetica, sans-serif; 8 | } 9 | 10 | *, 11 | *:before, 12 | *:after { 13 | box-sizing: inherit; 14 | } 15 | 16 | .photobooth { 17 | background: white; 18 | max-width: 150rem; 19 | margin: 2rem auto; 20 | border-radius: 2px; 21 | display: flex; 22 | flex-direction: column; 23 | justify-content: center; 24 | align-items: center; 25 | } 26 | 27 | h1 { 28 | text-align: center; 29 | font-family: 'Pacifico', cursive; 30 | color: #F46036; 31 | font-size: 48px; 32 | margin-bottom: 1vh; 33 | margin-top: 1vh; 34 | padding-top: 0; 35 | } 36 | 37 | button { 38 | height: 5vh; 39 | background-color: #2E294E; 40 | color: #fff; 41 | outline: 0; 42 | border: 0; 43 | border-radius: 0.3em; 44 | margin-bottom: 3vh; 45 | } 46 | 47 | .controls { 48 | margin-bottom: 3vh; 49 | } 50 | 51 | /*clearfix*/ 52 | .photobooth:after { 53 | content: ""; 54 | display: block; 55 | clear: both; 56 | } 57 | 58 | .photo { 59 | width: 100%; 60 | float: left; 61 | transform: rotateY(180deg); 62 | -webkit-transform:rotateY(180deg); /* Safari and Chrome */ 63 | -moz-transform:rotateY(180deg); /* Firefox */ 64 | margin-bottom: 1vh; 65 | } 66 | 67 | .player { 68 | position: absolute; 69 | top: 10px; 70 | right: 10px; 71 | width: 200px; 72 | transform: rotateY(180deg); 73 | -webkit-transform:rotateY(180deg); /* Safari and Chrome */ 74 | -moz-transform:rotateY(180deg); /* Firefox */ 75 | border-radius: 0.3em; 76 | } 77 | 78 | /* 79 | Strip! 80 | */ 81 | 82 | .strip { 83 | padding: 2rem; 84 | } 85 | 86 | .strip img { 87 | width: 100px; 88 | overflow-x: scroll; 89 | padding: 0.8rem 0.8rem 2.5rem 0.8rem; 90 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 91 | background: white; 92 | } 93 | 94 | .strip a:nth-child(5n + 1) img { 95 | transform: rotate(10deg); 96 | } 97 | .strip a:nth-child(5n + 2) img { 98 | transform: rotate(-2deg); 99 | } 100 | .strip a:nth-child(5n + 3) img { 101 | transform: rotate(8deg); 102 | } 103 | .strip a:nth-child(5n + 4) img { 104 | transform: rotate(-11deg); 105 | } 106 | .strip a:nth-child(5n + 5) img { 107 | transform: rotate(12deg); 108 | } 109 | 110 | 111 | /*# sourceMappingURL=/styles.dd855970.css.map */ -------------------------------------------------------------------------------- /19-Webcam-Fun/dist/styles.dd855970.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["src/styles.css"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"styles.dd855970.css","sourceRoot":"..","sourcesContent":["html {\r\n box-sizing: border-box;\r\n font-size: 10px;\r\n background-color: #f46036;\r\n background-image: url(\"data:image/svg+xml,%3Csvg width='80' height='80' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%232e294e' fill-opacity='0.2'%3E%3Cpath d='M50 50c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10zM10 10c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10S0 25.523 0 20s4.477-10 10-10zm10 8c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm40 40c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8z' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E\");\r\n padding: 2vw;\r\n font-family: Arial, Helvetica, sans-serif;\r\n}\r\n\r\n*,\r\n*:before,\r\n*:after {\r\n box-sizing: inherit;\r\n}\r\n\r\n.photobooth {\r\n background: white;\r\n max-width: 150rem;\r\n margin: 2rem auto;\r\n border-radius: 2px;\r\n display: flex;\r\n flex-direction: column;\r\n justify-content: center;\r\n align-items: center;\r\n}\r\n\r\nh1 {\r\n text-align: center;\r\n font-family: 'Pacifico', cursive;\r\n color: #F46036;\r\n font-size: 48px;\r\n margin-bottom: 1vh;\r\n margin-top: 1vh;\r\n padding-top: 0;\r\n}\r\n\r\nbutton {\r\n height: 5vh;\r\n background-color: #2E294E;\r\n color: #fff;\r\n outline: 0;\r\n border: 0;\r\n border-radius: 0.3em;\r\n margin-bottom: 3vh;\r\n}\r\n\r\n.controls {\r\n margin-bottom: 3vh;\r\n}\r\n\r\n/*clearfix*/\r\n.photobooth:after {\r\n content: \"\";\r\n display: block;\r\n clear: both;\r\n}\r\n\r\n.photo {\r\n width: 100%;\r\n float: left;\r\n transform: rotateY(180deg);\r\n -webkit-transform:rotateY(180deg); /* Safari and Chrome */\r\n -moz-transform:rotateY(180deg); /* Firefox */\r\n margin-bottom: 1vh;\r\n}\r\n\r\n.player {\r\n position: absolute;\r\n top: 10px;\r\n right: 10px;\r\n width: 200px;\r\n transform: rotateY(180deg);\r\n -webkit-transform:rotateY(180deg); /* Safari and Chrome */\r\n -moz-transform:rotateY(180deg); /* Firefox */\r\n border-radius: 0.3em;\r\n}\r\n\r\n/*\r\n Strip!\r\n*/\r\n\r\n.strip {\r\n padding: 2rem;\r\n}\r\n\r\n.strip img {\r\n width: 100px;\r\n overflow-x: scroll;\r\n padding: 0.8rem 0.8rem 2.5rem 0.8rem;\r\n box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);\r\n background: white;\r\n}\r\n\r\n.strip a:nth-child(5n + 1) img {\r\n transform: rotate(10deg);\r\n}\r\n.strip a:nth-child(5n + 2) img {\r\n transform: rotate(-2deg);\r\n}\r\n.strip a:nth-child(5n + 3) img {\r\n transform: rotate(8deg);\r\n}\r\n.strip a:nth-child(5n + 4) img {\r\n transform: rotate(-11deg);\r\n}\r\n.strip a:nth-child(5n + 5) img {\r\n transform: rotate(12deg);\r\n}\r\n"]} -------------------------------------------------------------------------------- /19-Webcam-Fun/dist/styles.dd855970.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["node_modules/parcel-bundler/src/builtins/bundle-url.js","node_modules/parcel-bundler/src/builtins/css-loader.js"],"names":["bundleURL","getBundleURLCached","getBundleURL","Error","err","matches","stack","match","getBaseURL","url","replace","exports","bundle","require","updateLink","link","newLink","cloneNode","onload","remove","href","split","Date","now","parentNode","insertBefore","nextSibling","cssTimeout","reloadCSS","setTimeout","links","document","querySelectorAll","i","length","module"],"mappings":"AAAA,ACAA,IDAIA,ACAAY,MAAM,GDAG,ACAAC,GDAG,IAAhB,ACAoB,CAAC,cAAD,CAApB;;ADCA,ACCA,SDDSZ,ACCAa,UAAT,CAAoBC,IAApB,EAA0B,CDD1B,GAA8B;AAC5B,ACCA,MDDI,ACCAC,CDDChB,MCCM,GDDX,ACCce,EDDE,ECCE,CAACE,SAAL,EAAd;ADAEjB,IAAAA,SAAS,GAAGE,YAAY,EAAxB;AACD,ACADc,EAAAA,OAAO,CAACE,MAAR,GAAiB,YAAY;AAC3BH,IAAAA,IAAI,CAACI,MAAL;ADCF,ACAC,GAFD,MDEOnB,SAAP;AACD;ACACgB,EAAAA,OAAO,CAACI,IAAR,GAAeL,IAAI,CAACK,IAAL,CAAUC,KAAV,CAAgB,GAAhB,EAAqB,CAArB,IAA0B,GAA1B,GAAgCC,IAAI,CAACC,GAAL,EAA/C;ADEF,ACDER,EAAAA,IAAI,CAACS,EDCEtB,QCDP,CAAgBuB,GDClB,GAAwB,MCDtB,CAA6BT,OAA7B,EAAsCD,IAAI,CAACW,WAA3C;ADEA,ACDD;ADEC,MAAI;AACF,ACDJ,IAAIC,MDCM,IAAIxB,ACDA,GAAG,EDCP,EAAN,ACDJ;ADEG,GAFD,CAEE,OAAOC,GAAP,EAAY;AACZ,ACFJ,QDEQC,CCFCuB,MDEM,GAAG,ACFlB,CDEmB,ECFE,GDEGxB,GAAG,CAACE,KAAV,EAAiBC,KAAjB,CAAuB,+DAAvB,CAAd;ACDF,MAAIoB,UAAJ,EAAgB;ADEd,ACDA,QDCItB,OAAJ,EAAa;AACX,ACDH,aDCUG,UAAU,CAACH,OAAO,CAAC,CAAD,CAAR,CAAjB;AACD;AACF,ACDDsB,EAAAA,UAAU,GAAGE,UAAU,CAAC,YAAY;AAClC,QAAIC,KAAK,GAAGC,QAAQ,CAACC,gBAAT,CAA0B,wBAA1B,CAAZ;ADEF,SAAO,GAAP;AACD,ACFG,SAAK,IAAIC,CAAC,GAAG,CAAb,EAAgBA,CAAC,GAAGH,KAAK,CAACI,MAA1B,EAAkCD,CAAC,EAAnC,EAAuC;AACrC,UAAIrB,MAAM,CAACJ,UAAP,CAAkBsB,KAAK,CAACG,CAAD,CAAL,CAASb,IAA3B,MAAqCR,MAAM,CAACV,YAAP,EAAzC,EAAgE;ADGtE,ACFQY,QAAAA,CDECN,SCFS,CDElB,ACFmBsB,CDECrB,GAApB,CCFwB,CDEC,ACFAwB,CAAD,CAAN,CAAV;ADGN,ACFK,SDEE,CAAC,KAAKxB,GAAN,EAAWC,OAAX,CAAmB,sEAAnB,EAA2F,IAA3F,IAAmG,GAA1G;AACD,ACFI;;ADILC,ACFIgB,IAAAA,GDEG,CAACzB,MCFM,GAAG,GDEjB,CCFI,EDEmBD,kBAAvB;AACAU,ACFG,GATsB,EASpB,EDEE,ACXkB,CDWjBH,ACXN,UDWF,GAAqBA,UAArB;ACDC;;AAED2B,MAAM,CAACxB,OAAP,GAAiBiB,SAAjB","file":"styles.dd855970.js","sourceRoot":"..","sourcesContent":["var bundleURL = null;\nfunction getBundleURLCached() {\n if (!bundleURL) {\n bundleURL = getBundleURL();\n }\n\n return bundleURL;\n}\n\nfunction getBundleURL() {\n // Attempt to find the URL of the current script and use that as the base URL\n try {\n throw new Error;\n } catch (err) {\n var matches = ('' + err.stack).match(/(https?|file|ftp|chrome-extension|moz-extension):\\/\\/[^)\\n]+/g);\n if (matches) {\n return getBaseURL(matches[0]);\n }\n }\n\n return '/';\n}\n\nfunction getBaseURL(url) {\n return ('' + url).replace(/^((?:https?|file|ftp|chrome-extension|moz-extension):\\/\\/.+)\\/[^/]+$/, '$1') + '/';\n}\n\nexports.getBundleURL = getBundleURLCached;\nexports.getBaseURL = getBaseURL;\n","var bundle = require('./bundle-url');\n\nfunction updateLink(link) {\n var newLink = link.cloneNode();\n newLink.onload = function () {\n link.remove();\n };\n newLink.href = link.href.split('?')[0] + '?' + Date.now();\n link.parentNode.insertBefore(newLink, link.nextSibling);\n}\n\nvar cssTimeout = null;\nfunction reloadCSS() {\n if (cssTimeout) {\n return;\n }\n\n cssTimeout = setTimeout(function () {\n var links = document.querySelectorAll('link[rel=\"stylesheet\"]');\n for (var i = 0; i < links.length; i++) {\n if (bundle.getBaseURL(links[i].href) === bundle.getBundleURL()) {\n updateLink(links[i]);\n }\n }\n\n cssTimeout = null;\n }, 50);\n}\n\nmodule.exports = reloadCSS;\n"]} -------------------------------------------------------------------------------- /19-Webcam-Fun/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webcam Fun - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 9 | 14 | 20 | 26 | 27 | 28 | 29 |
    30 |
    #19
    31 |
    of JavaScript30
    32 |
    33 |
    34 |
    35 |

    PhotoBooth

    36 | 37 |
    38 |
    39 | 40 | 41 | 42 | 43 |
    44 | 45 | 46 | 47 | 48 |
    49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 56 | 57 | 58 |
    59 | Click to download 60 |
    61 |
    62 |
    63 | 64 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /19-Webcam-Fun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "19-webcam-fun", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /19-Webcam-Fun/snap.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/19-Webcam-Fun/snap.mp3 -------------------------------------------------------------------------------- /19-Webcam-Fun/src/index.js: -------------------------------------------------------------------------------- 1 | const video = document.querySelector(".player"); 2 | const canvas = document.querySelector(".photo"); 3 | const ctx = canvas.getContext("2d"); 4 | const strip = document.querySelector(".strip"); 5 | const snap = document.querySelector(".snap"); 6 | 7 | function getVideo() { 8 | navigator.mediaDevices 9 | .getUserMedia({ video: true, audio: false }) 10 | .then(localMediaStream => { 11 | console.log(localMediaStream); 12 | video.srcObject = localMediaStream; 13 | video.play(); 14 | }) 15 | .catch(err => { 16 | console.error("Oh, NOOO!!!", err); 17 | }); 18 | } 19 | 20 | function paintToCanvas() { 21 | const width = video.videoWidth; 22 | const height = video.videoHeight; 23 | video.style.cssText = 24 | '-moz-transform: scale(-1, 1); \ 25 | -webkit-transform: scale(-1, 1); -o-transform: scale(-1, 1); \ 26 | transform: scale(-1, 1); filter: FlipH;'; 27 | canvas.width = width; 28 | canvas.height = height; 29 | 30 | return setInterval(() => { 31 | ctx.drawImage(video, 0, 0, width, height); 32 | // take pixels out 33 | let pixels = ctx.getImageData(0, 0, width, height); 34 | // mess with them 35 | // pixels = redEffect(pixels); 36 | 37 | pixels = rgbSplit(pixels); 38 | ctx.globalAlpha = 0.8; 39 | 40 | // put them back 41 | ctx.putImageData(pixels, 0, 0); 42 | // debugger; 43 | }, 16); 44 | } 45 | 46 | function greenScreen(pixels) { 47 | const levels = {}; 48 | 49 | document.querySelectorAll(".rgb input").forEach(input => { 50 | levels[input.name] = input.value; 51 | }); 52 | 53 | for (i = 0; i < pixels.data.length; i = i + 4) { 54 | red = pixels.data[i + 0]; 55 | green = pixels.data[i + 1]; 56 | blue = pixels.data[i + 2]; 57 | alpha = pixels.data[i + 3]; 58 | 59 | if ( 60 | red >= levels.rmin && 61 | green >= levels.gmin && 62 | blue >= levels.bmin && 63 | red <= levels.rmax && 64 | green <= levels.gmax && 65 | blue <= levels.bmax 66 | ) { 67 | // take it out! 68 | pixels.data[i + 3] = 0; 69 | } 70 | } 71 | 72 | return pixels; 73 | } 74 | 75 | function takePhoto() { 76 | // play sound 77 | snap.currentTime = 0; 78 | snap.play(); 79 | 80 | const data = canvas.toDataURL("image/jpeg"); 81 | const link = document.createElement("a"); 82 | link.href = data; 83 | link.setAttribute("download", "handsome"); 84 | link.innerHTML = `Smart Man`; 85 | strip.insertBefore(link, strip.firstChild); 86 | } 87 | 88 | function redEffect(pixels) { 89 | for (let i = 0; i < pixels.data.length; i += 4) { 90 | pixels.data[i + 0] += 100; //r 91 | pixels.data[i + 1] -= 50; //g 92 | pixels.data[i + 2] *= 0.5; //b 93 | } 94 | return pixels; 95 | } 96 | 97 | function rgbSplit(pixels) { 98 | for (let i = 0; i < pixels.data.length; i += 4) { 99 | pixels.data[i - 150] = pixels.data[i + 0]; // RED 100 | pixels.data[i + 500] = pixels.data[i + 1]; // GREEN 101 | pixels.data[i - 550] = pixels.data[i + 2]; // Blue 102 | } 103 | return pixels; 104 | } 105 | 106 | getVideo(); 107 | 108 | video.addEventListener("canplay", paintToCanvas); 109 | -------------------------------------------------------------------------------- /19-Webcam-Fun/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 10px; 4 | background-color: #f46036; 5 | background-image: url("data:image/svg+xml,%3Csvg width='80' height='80' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%232e294e' fill-opacity='0.2'%3E%3Cpath d='M50 50c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10zM10 10c0-5.523 4.477-10 10-10s10 4.477 10 10-4.477 10-10 10c0 5.523-4.477 10-10 10S0 25.523 0 20s4.477-10 10-10zm10 8c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm40 40c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8z' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 6 | padding: 2vw; 7 | font-family: Arial, Helvetica, sans-serif; 8 | } 9 | 10 | *, 11 | *:before, 12 | *:after { 13 | box-sizing: inherit; 14 | } 15 | 16 | .photobooth { 17 | background: white; 18 | max-width: 150rem; 19 | margin: 2rem auto; 20 | border-radius: 2px; 21 | display: flex; 22 | flex-direction: column; 23 | justify-content: center; 24 | align-items: center; 25 | } 26 | 27 | h1 { 28 | text-align: center; 29 | font-family: 'Pacifico', cursive; 30 | color: #F46036; 31 | font-size: 48px; 32 | margin-bottom: 1vh; 33 | margin-top: 1vh; 34 | padding-top: 0; 35 | } 36 | 37 | button { 38 | height: 5vh; 39 | background-color: #2E294E; 40 | color: #fff; 41 | outline: 0; 42 | border: 0; 43 | border-radius: 0.3em; 44 | margin-bottom: 3vh; 45 | } 46 | 47 | .controls { 48 | margin-bottom: 3vh; 49 | } 50 | 51 | /*clearfix*/ 52 | .photobooth:after { 53 | content: ""; 54 | display: block; 55 | clear: both; 56 | } 57 | 58 | .photo { 59 | width: 100%; 60 | float: left; 61 | transform: rotateY(180deg); 62 | -webkit-transform:rotateY(180deg); /* Safari and Chrome */ 63 | -moz-transform:rotateY(180deg); /* Firefox */ 64 | margin-bottom: 1vh; 65 | } 66 | 67 | .player { 68 | position: absolute; 69 | top: 10px; 70 | right: 10px; 71 | width: 200px; 72 | transform: rotateY(180deg); 73 | -webkit-transform:rotateY(180deg); /* Safari and Chrome */ 74 | -moz-transform:rotateY(180deg); /* Firefox */ 75 | border-radius: 0.3em; 76 | } 77 | 78 | /* 79 | Strip! 80 | */ 81 | 82 | .strip { 83 | padding: 2rem; 84 | } 85 | 86 | .strip img { 87 | width: 100px; 88 | overflow-x: scroll; 89 | padding: 0.8rem 0.8rem 2.5rem 0.8rem; 90 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 91 | background: white; 92 | } 93 | 94 | .strip a:nth-child(5n + 1) img { 95 | transform: rotate(10deg); 96 | } 97 | .strip a:nth-child(5n + 2) img { 98 | transform: rotate(-2deg); 99 | } 100 | .strip a:nth-child(5n + 3) img { 101 | transform: rotate(8deg); 102 | } 103 | .strip a:nth-child(5n + 4) img { 104 | transform: rotate(-11deg); 105 | } 106 | .strip a:nth-child(5n + 5) img { 107 | transform: rotate(12deg); 108 | } 109 | -------------------------------------------------------------------------------- /20-Speech-Recognition/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Speech Detection - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #20
    30 |
    of JavaScript30
    31 |
    32 |
    33 |

    Speak to Type

    34 | P.S. Do not say any synonym of shit or else face consequences 35 |
    36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /20-Speech-Recognition/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "20-speech-recognition", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html", 9 | "dev": "browser-sync start --directory --server --files \"*.css, *.html, *.js\"" 10 | }, 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "@babel/core": "7.2.0", 14 | "parcel-bundler": "^1.6.1", 15 | "browser-sync": "^2.12.5 <2.27.11" 16 | }, 17 | "keywords": [] 18 | } 19 | -------------------------------------------------------------------------------- /20-Speech-Recognition/src/index.js: -------------------------------------------------------------------------------- 1 | window.SpeechRecognition = 2 | window.SpeechRecognition || window.webkitSpeechRecognition; 3 | 4 | const recognition = new SpeechRecognition(); 5 | recognition.interimResults = true; 6 | 7 | let p = document.createElement("p"); 8 | const words = document.querySelector(".words"); 9 | words.appendChild(p); 10 | 11 | recognition.addEventListener("result", e => { 12 | const transcript = Array.from(e.results) 13 | .map(result => result[0]) 14 | .map(result => result.transcript) 15 | .join(""); 16 | 17 | const poopScript = transcript.replace(/poop|poo|shit|java|dump/gi, "💩"); 18 | p.textContent = poopScript; 19 | 20 | // p.textContent = transcript; 21 | if (e.results[0].isFinal) { 22 | p = document.createElement("p"); 23 | words.appendChild(p); 24 | } 25 | }); 26 | 27 | recognition.addEventListener("end", recognition.start); 28 | recognition.start(); 29 | -------------------------------------------------------------------------------- /20-Speech-Recognition/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10px; 3 | } 4 | 5 | body { 6 | background-color: #f38181; 7 | background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 20.5V18H0v-2h20v-2H0v-2h20v-2H0V8h20V6H0V4h20V2H0V0h22v20h2V0h2v20h2V0h2v20h2V0h2v20h2V0h2v20h2v2H20v-1.5zM0 20h2v20H0V20zm4 0h2v20H4V20zm4 0h2v20H8V20zm4 0h2v20h-2V20zm4 0h2v20h-2V20zm4 4h20v2H20v-2zm0 4h20v2H20v-2zm0 4h20v2H20v-2zm0 4h20v2H20v-2z' fill='%23fce38a' fill-opacity='0.25' fill-rule='evenodd'/%3E%3C/svg%3E"); 8 | font-family: 'helvetica neue'; 9 | font-weight: 200; 10 | font-size: 20px; 11 | display: flex; 12 | justify-content: center; 13 | flex-direction: column; 14 | font-family: sans-serif; 15 | } 16 | 17 | h1, small { 18 | color: #eaffd0; 19 | text-align: center; 20 | } 21 | 22 | .words { 23 | width: 500px; 24 | max-width: 500px; 25 | margin: 50px auto; 26 | background: #95e1d3; 27 | border-radius: 5px; 28 | box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.1); 29 | padding: 1rem 2rem 1rem 5rem; 30 | background: -webkit-gradient( 31 | linear, 32 | 0 0, 33 | 0 100%, 34 | from(#d9eaf3), 35 | color-stop(4%, #95e1d3) 36 | ) 37 | 0 4px; 38 | background-size: 100% 3rem; 39 | position: relative; 40 | line-height: 3rem; 41 | } 42 | 43 | p { 44 | margin: 0 0 3rem; 45 | } 46 | 47 | .words:before { 48 | content: ''; 49 | position: absolute; 50 | width: 4px; 51 | top: 0; 52 | left: 30px; 53 | bottom: 0; 54 | border: 1px solid; 55 | border-color: transparent #efe4e4; 56 | } 57 | -------------------------------------------------------------------------------- /21-Geolocation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Geolocation - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 9 | 14 | 20 | 26 | 27 | 28 | 29 |
    30 |
    #21
    31 |
    of JavaScript30
    32 |
    33 |
    34 | 45 | 46 | 50 | 51 | 55 | 59 | 63 | 67 | 71 | 72 | 73 | 74 | 75 |

    76 | 0 77 | KM/H 78 |

    79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /21-Geolocation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "21-geolocation", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "browser-sync start --directory --server --files \"*.css, *.html, *.js\"" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "browser-sync": "^2.12.5 <2.27.11" 12 | }, 13 | "keywords": [] 14 | } 15 | -------------------------------------------------------------------------------- /21-Geolocation/src/index.js: -------------------------------------------------------------------------------- 1 | const arrow = document.querySelector('.arrow'); 2 | const speed = document.querySelector('.speed-value'); 3 | 4 | navigator.geolocation.watchPosition((data) => { 5 | console.log(data); 6 | speed.textContent = (data.coords.speed * 3.6).toFixed(2); 7 | arrow.style.transform = `rotate(${data.coords.heading}deg)` 8 | }, (err) => { 9 | console.log(err); 10 | alert('Uh-oh, you need to allow location permission for this application to run.') 11 | }); -------------------------------------------------------------------------------- /21-Geolocation/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 100px; 3 | } 4 | 5 | body { 6 | margin: 0; 7 | font-family: sans-serif; 8 | min-height: 100vh; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | flex-direction: column; 13 | background: radial-gradient(black 15%, transparent 16%) 0 0, 14 | radial-gradient(black 15%, transparent 16%) 8px 8px, 15 | radial-gradient(rgba(255, 255, 255, 0.1) 15%, transparent 20%) 0 1px, 16 | radial-gradient(rgba(255, 255, 255, 0.1) 15%, transparent 20%) 8px 9px; 17 | background-color: #282828; 18 | background-size: 16px 16px; 19 | background-attachment: fixed; 20 | } 21 | 22 | .arrow { 23 | width: 250px; 24 | overflow: hidden; 25 | transition: all 0.2s; 26 | transform: rotate(0deg); 27 | display: inline-block; 28 | } 29 | 30 | h1 { 31 | color: white; 32 | font-weight: 100; 33 | font-size: 60px; 34 | display: flex; 35 | align-items: center; 36 | } 37 | 38 | .units { 39 | font-size: 15px; 40 | } 41 | /*Compass: https://thenounproject.com/search/?q=compass&i=592352*/ 42 | -------------------------------------------------------------------------------- /22-Follow-Along-Link/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 👀 Follow Along Nav - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #22
    30 |
    of JavaScript30
    31 |
    32 |
    33 |

    Follow Along Link

    34 | 43 | 44 |
    45 |

    46 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. 47 | Est explicabo unde natus necessitatibus esse obcaecati 48 | distinctio, aut itaque, qui vitae! 49 |

    50 |

    51 | Aspernatur sapiente quae sint soluta modi, atque 52 | praesentium laborum pariatur earum quaerat cupiditate 53 | consequuntur facilis ullam dignissimos, aperiam quam veniam. 54 |

    55 |

    56 | Cum ipsam quod, incidunt sit ex tempore placeat maxime 57 | corrupti possimus veritatis ipsum fugit 58 | recusandae est doloremque? Hic, quibusdam, nulla. 59 |

    60 |

    61 | Esse quibusdam, ad, ducimus cupiditate nulla, quae magni 62 | odit totam ut consequatur eveniet sunt quam provident 63 | sapiente dicta neque quod. 64 |

    65 |

    66 | Aliquam dicta sequi culpa fugiat 67 | consequuntur pariatur optio ad minima, maxime 68 | odio, distinctio magni impedit tempore enim repellendus 69 | repudiandae quas! 70 |

    71 |
    72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /22-Follow-Along-Link/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "follow-along-link", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /22-Follow-Along-Link/src/index.js: -------------------------------------------------------------------------------- 1 | const triggers = document.querySelectorAll("a"); 2 | const highlight = document.createElement("span"); 3 | highlight.classList.add("highlight"); 4 | document.body.appendChild(highlight); 5 | 6 | function highlightLink() { 7 | const linkCoords = this.getBoundingClientRect(); 8 | console.log(linkCoords); 9 | 10 | const coords = { 11 | width: linkCoords.width, 12 | height: linkCoords.height, 13 | top: linkCoords.top + window.scrollY, 14 | left: linkCoords.left + window.scrollX 15 | }; 16 | 17 | highlight.style.width = `${coords.width}px`; 18 | highlight.style.height = `${coords.height}px`; 19 | highlight.style.transform = `translate(${coords.left}px, ${coords.top}px)`; 20 | } 21 | triggers.forEach(a => a.addEventListener("mouseenter", highlightLink)); 22 | -------------------------------------------------------------------------------- /22-Follow-Along-Link/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, 6 | *:before, 7 | *:after { 8 | box-sizing: inherit; 9 | } 10 | 11 | body { 12 | min-height: 100vh; 13 | margin: 0; /* Important! */ 14 | font-family: sans-serif; 15 | background-color: #00adb5; 16 | background-image: url("data:image/svg+xml,%3Csvg width='52' height='26' viewBox='0 0 52 26' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23eeeeee' fill-opacity='0.1'%3E%3Cpath d='M10 10c0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4v2c-3.314 0-6-2.686-6-6 0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6zm25.464-1.95l8.486 8.486-1.414 1.414-8.486-8.486 1.414-1.414z' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 17 | } 18 | 19 | h1{ 20 | text-align: center; 21 | color: #eeeeee; 22 | } 23 | 24 | .wrapper { 25 | margin: 0 auto; 26 | max-width: 500px; 27 | font-size: 20px; 28 | line-height: 2; 29 | position: relative; 30 | } 31 | 32 | a { 33 | text-decoration: none; 34 | color: black; 35 | background: rgba(0, 0, 0, 0.05); 36 | border-radius: 20px; 37 | } 38 | 39 | .highlight { 40 | transition: all 0.2s; 41 | border-bottom: 2px solid #eeeeee; 42 | position: absolute; 43 | top: 0; 44 | background: #eeeeee; 45 | left: 0; 46 | z-index: -1; 47 | border-radius: 20px; 48 | display: block; 49 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 50 | } 51 | 52 | .menu { 53 | padding: 0; 54 | display: flex; 55 | list-style: none; 56 | justify-content: center; 57 | margin: 100px 0; 58 | } 59 | 60 | .menu a { 61 | display: inline-block; 62 | padding: 5px; 63 | margin: 0 20px; 64 | color: #393e46; 65 | } 66 | -------------------------------------------------------------------------------- /23-Speech-Synthesis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Speech Synthesis - JavaScript30 by Ayush Gupta 6 | 11 | 12 | 13 | 18 | 24 | 30 | 31 | 32 | 33 |
    34 |
    #23
    35 |
    of JavaScript30
    36 |
    37 |
    38 |
    39 |

    The Voiceinator 5000

    40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
    55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /23-Speech-Synthesis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "23-speech-synthesis", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /23-Speech-Synthesis/src/index.js: -------------------------------------------------------------------------------- 1 | const msg = new SpeechSynthesisUtterance(); 2 | let voices = []; 3 | const voicesDropdown = document.querySelector('[name="voice"]'); 4 | const options = document.querySelectorAll('[type="range"], [name="text"]'); 5 | const speakButton = document.querySelector('#speak'); 6 | const stopButton = document.querySelector('#stop'); 7 | 8 | msg.text = document.querySelector('[name="text"]').value; 9 | 10 | function populateVoices() { 11 | voices = this.getVoices(); 12 | voicesDropdown.innerHTML = voices 13 | .filter((voice) => voice.lang.includes('en')) 14 | .map( 15 | (voice) => 16 | `` 17 | ) 18 | .join(''); 19 | } 20 | 21 | function setVoice() { 22 | msg.voice = voices.find((voice) => voice.name === this.value); 23 | toggle(); 24 | } 25 | 26 | function toggle(startOver = true) { 27 | speechSynthesis.cancel(); 28 | if (startOver) { 29 | speechSynthesis.speak(msg); 30 | } 31 | } 32 | 33 | function setOption() { 34 | msg[this.name] = this.value; 35 | toggle(); 36 | } 37 | 38 | speechSynthesis.addEventListener('voiceschanged', populateVoices); 39 | voicesDropdown.addEventListener('change', setVoice); 40 | options.forEach((option) => option.addEventListener('change', setOption)); 41 | speakButton.addEventListener('click', toggle); 42 | stopButton.addEventListener('click', () => toggle(false)); 43 | -------------------------------------------------------------------------------- /23-Speech-Synthesis/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10px; 3 | box-sizing: border-box; 4 | } 5 | 6 | *, *:before, *:after { 7 | box-sizing: inherit; 8 | } 9 | 10 | body { 11 | margin: 0; 12 | padding: 0; 13 | font-family: sans-serif; 14 | background-color: #3BC1AC; 15 | display: flex; 16 | min-height: 100vh; 17 | align-items: center; 18 | background-color: #ff9999; 19 | background-image: url("data:image/svg+xml,%3Csvg width='180' height='180' viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M81.28 88H68.413l19.298 19.298L81.28 88zm2.107 0h13.226L90 107.838 83.387 88zm15.334 0h12.866l-19.298 19.298L98.72 88zm-32.927-2.207L73.586 78h32.827l.5.5 7.294 7.293L115.414 87l-24.707 24.707-.707.707L64.586 87l1.207-1.207zm2.62.207L74 80.414 79.586 86H68.414zm16 0L90 80.414 95.586 86H84.414zm16 0L106 80.414 111.586 86h-11.172zm-8-6h11.173L98 85.586 92.414 80zM82 85.586L87.586 80H76.414L82 85.586zM17.414 0L.707 16.707 0 17.414V0h17.414zM4.28 0L0 12.838V0h4.28zm10.306 0L2.288 12.298 6.388 0h8.198zM180 17.414L162.586 0H180v17.414zM165.414 0l12.298 12.298L173.612 0h-8.198zM180 12.838L175.72 0H180v12.838zM0 163h16.413l.5.5 7.294 7.293L25.414 172l-8 8H0v-17zm0 10h6.613l-2.334 7H0v-7zm14.586 7l7-7H8.72l-2.333 7h8.2zM0 165.414L5.586 171H0v-5.586zM10.414 171L16 165.414 21.586 171H10.414zm-8-6h11.172L8 170.586 2.414 165zM180 163h-16.413l-7.794 7.793-1.207 1.207 8 8H180v-17zm-14.586 17l-7-7h12.865l2.333 7h-8.2zM180 173h-6.613l2.334 7H180v-7zm-21.586-2l5.586-5.586 5.586 5.586h-11.172zM180 165.414L174.414 171H180v-5.586zm-8 5.172l5.586-5.586h-11.172l5.586 5.586zM152.933 25.653l1.414 1.414-33.94 33.942-1.416-1.416 33.943-33.94zm1.414 127.28l-1.414 1.414-33.942-33.94 1.416-1.416 33.94 33.943zm-127.28 1.414l-1.414-1.414 33.94-33.942 1.416 1.416-33.943 33.94zm-1.414-127.28l1.414-1.414 33.942 33.94-1.416 1.416-33.94-33.943zM0 85c2.21 0 4 1.79 4 4s-1.79 4-4 4v-8zm180 0c-2.21 0-4 1.79-4 4s1.79 4 4 4v-8zM94 0c0 2.21-1.79 4-4 4s-4-1.79-4-4h8zm0 180c0-2.21-1.79-4-4-4s-4 1.79-4 4h8z' fill='%23ffc8c8' fill-opacity='0.43' fill-rule='evenodd'/%3E%3C/svg%3E"); 20 | } 21 | 22 | .voiceinator { 23 | padding: 2rem; 24 | width: 50rem; 25 | margin: 0 auto; 26 | border-radius: 1rem; 27 | position: relative; 28 | background: white; 29 | overflow: hidden; 30 | z-index: 1; 31 | box-shadow: 0 0 5px 5px rgba(0,0,0,0.1); 32 | } 33 | 34 | h1 { 35 | width: calc(100% + 4rem); 36 | margin: -2rem 0 2rem -2rem; 37 | padding: .5rem; 38 | background: #3fc1c9; 39 | border-bottom: 5px solid #ffc8c8; 40 | text-align: center; 41 | font-size: 5rem; 42 | font-weight: 100; 43 | font-family: 'Pacifico', cursive; 44 | text-shadow: 3px 3px 0 #ffc8c8; 45 | /* color: white; */ 46 | } 47 | 48 | .voiceinator input, 49 | .voiceinator button, 50 | .voiceinator select, 51 | .voiceinator textarea { 52 | width: 100%; 53 | display: block; 54 | margin: 10px 0; 55 | padding: 10px; 56 | border: 0; 57 | font-size: 2rem; 58 | background: #F7F7F7; 59 | outline: 0; 60 | } 61 | 62 | textarea { 63 | height: 20rem; 64 | } 65 | 66 | input[type="select"] { 67 | 68 | } 69 | 70 | .voiceinator button { 71 | background: #3fc1c9; 72 | border: 0; 73 | width: 49%; 74 | float: left; 75 | font-family: 'Pacifico', cursive; 76 | margin-bottom: 0; 77 | font-size: 2rem; 78 | border-bottom: 5px solid #ffc8c8; 79 | cursor: pointer; 80 | position: relative; 81 | } 82 | 83 | .voiceinator button:active { 84 | top: 2px; 85 | } 86 | 87 | .voiceinator button:nth-of-type(1) { 88 | margin-right: 2%; 89 | } -------------------------------------------------------------------------------- /24-Sticky-Nav/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sticky-nav", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /24-Sticky-Nav/src/index.js: -------------------------------------------------------------------------------- 1 | const nav = document.querySelector("#main"); 2 | const topOfNav = nav.offsetTop; 3 | 4 | function fixNav() { 5 | if (window.scrollY >= topOfNav) { 6 | document.body.style.paddingTop = nav.offsetHeight + "px"; 7 | document.body.classList.add("fixed-nav"); 8 | } else { 9 | document.body.style.paddingTop = 0; 10 | document.body.classList.remove("fixed-nav"); 11 | } 12 | } 13 | 14 | window.addEventListener("scroll", fixNav); 15 | -------------------------------------------------------------------------------- /24-Sticky-Nav/src/styles.css: -------------------------------------------------------------------------------- 1 | #project-tag { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | background-color: yellow; 6 | border: 1px solid transparent; 7 | /* border-radius: 0px 3px 3px 0px; */ 8 | border-bottom-right-radius: 3px; 9 | color: black; 10 | font-weight: bolder; 11 | font-family: monospace; 12 | font-size: medium; 13 | height: 5vh; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | padding: 5px 15px; 19 | transition-timing-function: linear; 20 | box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); 21 | } 22 | 23 | html { 24 | box-sizing: border-box; 25 | background: #444f5a; 26 | font-family: "helvetica neue"; 27 | font-size: 20px; 28 | font-weight: 200; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | } 34 | 35 | *, 36 | *:before, 37 | *:after { 38 | box-sizing: inherit; 39 | } 40 | 41 | .site-wrap { 42 | max-width: 700px; 43 | margin: 70px auto; 44 | background: #ff9999; 45 | padding: 40px; 46 | text-align: justify; 47 | box-shadow: 0 0 10px 5px rgba(0, 0, 0, 0.05); 48 | transform: scale(0.98); 49 | transition: transform 0.5s; 50 | } 51 | 52 | .fixed-nav .site-wrap { 53 | transform: scale(1); 54 | } 55 | 56 | header { 57 | text-align: center; 58 | height: 50vh; 59 | background: url(http://wes.io/iEgP/wow-so-deep.jpg) bottom center no-repeat; 60 | background-size: cover; 61 | display: flex; 62 | align-items: center; 63 | justify-content: center; 64 | } 65 | 66 | h1 { 67 | color: #ffc8c8; 68 | font-size: 7vw; 69 | text-shadow: 3px 4px 0 rgba(0, 0, 0, 0.2); 70 | } 71 | 72 | nav { 73 | background: #ff9999; 74 | top: 0; 75 | width: 100%; 76 | transition: all 0.5s; 77 | position: relative; 78 | z-index: 1; 79 | } 80 | 81 | .fixed-nav nav { 82 | position: fixed; 83 | box-shadow: 0 5px rgba(0, 0, 0, 0.2); 84 | } 85 | 86 | nav ul { 87 | margin: 0; 88 | padding: 0; 89 | list-style: none; 90 | display: flex; 91 | } 92 | 93 | nav li { 94 | flex: 1; 95 | text-align: center; 96 | display: flex; 97 | justify-content: center; 98 | align-items: center; 99 | } 100 | 101 | li.logo { 102 | max-width: 0; 103 | overflow: hidden; 104 | background: white; 105 | transition: all 0.5s; 106 | font-weight: 600; 107 | font-size: 30px; 108 | } 109 | 110 | .fixed-nav li.logo { 111 | max-width: 500px; 112 | } 113 | 114 | li.logo a { 115 | color: black; 116 | } 117 | 118 | nav a { 119 | text-decoration: none; 120 | padding: 20px; 121 | display: inline-block; 122 | color: white; 123 | transition: all 0.2s; 124 | text-transform: uppercase; 125 | } 126 | -------------------------------------------------------------------------------- /25-EventCapture-Propogation-Bubbling/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Understanding JavaScript's Capture - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #25
    30 |
    of JavaScript30
    31 |
    32 |
    33 |

    JavaScript Event Capture & Bubbling

    34 |
    35 |
    36 |
    37 |
    38 |
    39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /25-EventCapture-Propogation-Bubbling/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "25-eventpropogation-bubbling-once", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /25-EventCapture-Propogation-Bubbling/src/index.js: -------------------------------------------------------------------------------- 1 | const divs = document.querySelectorAll("div"); 2 | const button = document.querySelector("button"); 3 | function logText(e) { 4 | console.log(this.classList.value); 5 | e.stopPropagation(); // stop bubbling! 6 | console.log(this); 7 | } 8 | divs.forEach(div => 9 | div.addEventListener("click", logText, { 10 | capture: false, 11 | once: true 12 | }) 13 | ); 14 | button.addEventListener( 15 | "click", 16 | () => { 17 | console.log("Click!!!"); 18 | }, 19 | { 20 | once: true 21 | } 22 | ); 23 | -------------------------------------------------------------------------------- /25-EventCapture-Propogation-Bubbling/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | text-align: center; 4 | font-family: monospace; 5 | color: #EFCB68; 6 | background-color: #160c28; 7 | background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23efcb68' fill-opacity='0.17' fill-rule='evenodd'/%3E%3C/svg%3E"); 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | flex-direction: column; 12 | } 13 | 14 | *, 15 | *:before, 16 | *:after { 17 | box-sizing: inherit; 18 | } 19 | .one { 20 | background: #E65F5C; 21 | width: 100%; 22 | padding: 100px; 23 | border-radius: 0.3em; 24 | margin-bottom: 10px; 25 | margin-top: 5vh; 26 | } 27 | .two { 28 | background: #406E8E; 29 | width: 100%; 30 | padding: 100px; 31 | } 32 | .three { 33 | background: #0CBABA; 34 | width: 100%; 35 | padding: 100px; 36 | } 37 | 38 | button { 39 | background-color: #EFCB68; 40 | color: #160c28; 41 | border: 0; 42 | outline: 0; 43 | border-radius: 0.3em; 44 | height: 3vh; 45 | font-weight: bold; 46 | text-transform: uppercase; 47 | min-width: 15vh; 48 | } 49 | -------------------------------------------------------------------------------- /26-Stripe-Nav/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Strip Nav - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #26
    30 |
    of JavaScript30
    31 |
    32 |
    33 |

    Ayush Gupta

    34 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /26-Stripe-Nav/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "26-stripe-nav", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /26-Stripe-Nav/src/index.js: -------------------------------------------------------------------------------- 1 | const triggers = document.querySelectorAll(".cool > li"); 2 | const background = document.querySelector(".dropdownBackground"); 3 | const nav = document.querySelector(".top"); 4 | 5 | function handleEnter() { 6 | this.classList.add("trigger-enter"); 7 | setTimeout(() => { 8 | this.classList.contains("trigger-enter") && 9 | this.classList.add("trigger-enter-active"); 10 | }, 150); 11 | background.classList.add("open"); 12 | 13 | const dropdown = this.querySelector(".dropdown"); 14 | const dropdownCoords = dropdown.getBoundingClientRect(); 15 | const navCoords = nav.getBoundingClientRect(); 16 | 17 | const coords = { 18 | height: dropdownCoords.height, 19 | width: dropdownCoords.width, 20 | top: dropdownCoords.top - navCoords.top, 21 | left: dropdownCoords.left - navCoords.left 22 | }; 23 | 24 | background.style.setProperty("width", `${coords.width}px`); 25 | background.style.setProperty("height", `${coords.height}px`); 26 | background.style.setProperty( 27 | "transform", 28 | `translate(${coords.left}px, ${coords.top}px)` 29 | ); 30 | } 31 | 32 | function handleLeave() { 33 | this.classList.remove("trigger-enter", "tigger-enter-active"); 34 | background.classList.remove("open"); 35 | } 36 | 37 | triggers.forEach(trigger => 38 | trigger.addEventListener("mouseenter", handleEnter) 39 | ); 40 | triggers.forEach(trigger => 41 | trigger.addEventListener("mouseleave", handleLeave) 42 | ); 43 | -------------------------------------------------------------------------------- /27-Click-Drag-Scroll/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Click and Drag - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #27
    30 |
    of JavaScript30
    31 |
    32 |
    33 |
    34 |
    01
    35 |
    02
    36 |
    03
    37 |
    04
    38 |
    05
    39 |
    06
    40 |
    07
    41 |
    08
    42 |
    09
    43 |
    10
    44 |
    11
    45 |
    12
    46 |
    13
    47 |
    14
    48 |
    15
    49 |
    16
    50 |
    17
    51 |
    18
    52 |
    19
    53 |
    20
    54 |
    21
    55 |
    22
    56 |
    23
    57 |
    24
    58 |
    25
    59 |
    26
    60 |
    27
    61 |
    28
    62 |
    29
    63 |
    30
    64 |
    65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /27-Click-Drag-Scroll/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "27-click-drag-scroll", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /27-Click-Drag-Scroll/src/index.js: -------------------------------------------------------------------------------- 1 | const slider = document.querySelector(".items"); 2 | let isDown = false; 3 | let startX; 4 | let scrollLeft; 5 | 6 | slider.addEventListener("mousedown", e => { 7 | isDown = true; 8 | slider.classList.add("active"); 9 | startX = e.pageX - slider.offsetLeft; 10 | scrollLeft = slider.scrollLeft; 11 | }); 12 | 13 | slider.addEventListener("mouseleave", () => { 14 | isDown = false; 15 | slider.classList.remove("active"); 16 | }); 17 | 18 | slider.addEventListener("mouseup", () => { 19 | isDown = false; 20 | slider.classList.remove("active"); 21 | }); 22 | 23 | slider.addEventListener("mousemove", e => { 24 | if (!isDown) return; 25 | e.preventDefault(); 26 | const x = e.pageX - slider.offsetLeft; 27 | const walk = (x - startX) * 3; 28 | slider.scrollLeft = scrollLeft - walk; 29 | }); 30 | -------------------------------------------------------------------------------- /27-Click-Drag-Scroll/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | background-color: #111111; 4 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg fill='%23808080' fill-opacity='0.22'%3E%3Cpolygon fill-rule='evenodd' points='8 4 12 6 8 8 6 12 4 8 0 6 4 4 6 0 8 4'/%3E%3C/g%3E%3C/svg%3E"); 5 | 6 | } 7 | *, 8 | *:before, 9 | *:after { 10 | box-sizing: inherit; 11 | } 12 | 13 | body { 14 | min-height: 100vh; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | font-family: sans-serif; 19 | font-size: 20px; 20 | margin: 0; 21 | } 22 | 23 | .items { 24 | height: 85vh; 25 | padding: 100px; 26 | width: 100%; 27 | border: 1px solid white; 28 | border-radius: 10px; 29 | overflow-x: scroll; 30 | overflow-y: hidden; 31 | white-space: nowrap; 32 | user-select: none; 33 | cursor: pointer; 34 | transition: all 0.2s; 35 | transform: scale(0.98); 36 | will-change: transform; 37 | position: relative; 38 | background: rgba(255, 255, 255, 0.05); 39 | font-size: 0; 40 | perspective: 500px; 41 | } 42 | 43 | .items.active { 44 | background: rgba(255, 255, 255, 0.1); 45 | cursor: grabbing; 46 | cursor: -webkit-grabbing; 47 | transform: scale(1); 48 | } 49 | 50 | .item { 51 | width: 200px; 52 | height: calc(100% - 10px); 53 | display: inline-flex; 54 | align-items: center; 55 | justify-content: center; 56 | border-radius: 10px; 57 | font-size: 80px; 58 | font-weight: 100; 59 | color: rgba(0, 0, 0, 0.15); 60 | box-shadow: inset 0 0 0 10px rgba(0, 0, 0, 0.15); 61 | } 62 | 63 | .item:nth-child(5n + 1) { 64 | background: #2f855a; 65 | } 66 | .item:nth-child(5n + 2) { 67 | background: #38a169; 68 | } 69 | .item:nth-child(5n + 3) { 70 | background: #48bb78; 71 | } 72 | .item:nth-child(5n + 4) { 73 | background: #68d391; 74 | } 75 | .item:nth-child(5n + 5) { 76 | background: #9ae6b4; 77 | } 78 | 79 | .item:nth-child(5n + 6) { 80 | background: #b83280; 81 | } 82 | .item:nth-child(5n + 7) { 83 | background: #d53f8c; 84 | } 85 | .item:nth-child(5n + 8) { 86 | background: #ed64a6; 87 | } 88 | .item:nth-child(5n + 9) { 89 | background: #f687b3; 90 | } 91 | .item:nth-child(5n + 10) { 92 | background: #fbb6ce; 93 | } 94 | 95 | .item:nth-child(5n + 11) { 96 | background: #6B46C1; 97 | } 98 | .item:nth-child(5n + 12) { 99 | background: #805AD5; 100 | } 101 | .item:nth-child(5n + 13) { 102 | background: #9F7AEA; 103 | } 104 | .item:nth-child(5n + 14) { 105 | background: #B794F4; 106 | } 107 | .item:nth-child(5n + 15) { 108 | background: #D6BCFA; 109 | } 110 | 111 | .item:nth-child(5n + 16) { 112 | background: #C05621; 113 | } 114 | .item:nth-child(5n + 17) { 115 | background: #DD6B20; 116 | } 117 | .item:nth-child(5n + 18) { 118 | background: #ED8936; 119 | } 120 | .item:nth-child(5n + 19) { 121 | background: #F6AD55; 122 | } 123 | .item:nth-child(5n + 20) { 124 | background: #FBD38D; 125 | } 126 | 127 | .item:nth-child(5n + 21) { 128 | background: #C53030; 129 | } 130 | .item:nth-child(5n + 22) { 131 | background: #E53E3E; 132 | } 133 | .item:nth-child(5n + 23) { 134 | background: #F56565; 135 | } 136 | .item:nth-child(5n + 24) { 137 | background: #FC8181; 138 | } 139 | .item:nth-child(5n + 25) { 140 | background: #FEB2B2; 141 | } 142 | 143 | .item:nth-child(5n + 26) { 144 | background: #2C7A7B; 145 | } 146 | .item:nth-child(5n + 27) { 147 | background: #319795; 148 | } 149 | .item:nth-child(5n + 28) { 150 | background: #38B2AC; 151 | } 152 | .item:nth-child(5n + 29) { 153 | background: #4FD1C5; 154 | } 155 | .item:nth-child(5n + 30) { 156 | background: #81E6D9; 157 | } 158 | 159 | 160 | 161 | .item:nth-child(even) { 162 | transform: scaleX(1.31) rotateY(40deg); 163 | } 164 | .item:nth-child(odd) { 165 | transform: scaleX(1.31) rotateY(-40deg); 166 | } 167 | -------------------------------------------------------------------------------- /28-Video-Speed-Controller/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Video Speed Scrubber - JavaScript30 by Ayush Gupta 6 | 7 | 8 | 13 | 19 | 25 | 26 | 27 | 28 |
    29 |
    #28
    30 |
    of JavaScript30
    31 |
    32 |
    33 |

    Video Speed Controller

    34 |
    35 | 43 |
    44 |
    45 |
    46 |
    47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /28-Video-Speed-Controller/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "28-video-speed-controller", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } -------------------------------------------------------------------------------- /28-Video-Speed-Controller/src/index.js: -------------------------------------------------------------------------------- 1 | const speed = document.querySelector(".speed"); 2 | const bar = speed.querySelector(".speed-bar"); 3 | const video = document.querySelector(".flex"); 4 | 5 | function handleMove(e) { 6 | const y = e.pageY - this.offsetTop; 7 | const percent = y / this.offsetHeight; 8 | const min = 0.4; 9 | const max = 6; 10 | const height = Math.round(percent * 100) + "%"; 11 | bar.style.height = height; 12 | 13 | const playbackRate = percent * (max - min) + min; 14 | bar.textContent = playbackRate.toFixed(2) + "x"; 15 | video.playbackRate = playbackRate; 16 | } 17 | 18 | speed.addEventListener("mousemove", handleMove); 19 | -------------------------------------------------------------------------------- /28-Video-Speed-Controller/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | min-height: 100vh; 7 | background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), 8 | url('http://www.lisbonazulejos.com/assets/images/svg/azulejo-26.svg'); 9 | /* opacity: 0.5; */ 10 | font-family: sans-serif; 11 | flex-direction: column; 12 | } 13 | h1 { 14 | color: #fff; 15 | font-size: calc(1em + 2vw); 16 | font-weight: 900; 17 | text-shadow: 4px 4px 0px #6a82fb, 7px 7px 0px rgba(0, 0, 0, 0.5); 18 | margin-bottom: 5vh; 19 | } 20 | 21 | .wrapper { 22 | width: 850px; 23 | display: flex; 24 | } 25 | 26 | video { 27 | box-shadow: 0 0 1px 3px rgba(0, 0, 0, 0.1); 28 | } 29 | 30 | .speed { 31 | background: #efefef; 32 | flex: 1; 33 | display: flex; 34 | align-items: flex-start; 35 | margin: 10px; 36 | border-radius: 50px; 37 | box-shadow: 0 0 1px 3px rgba(0, 0, 0, 0.1); 38 | overflow: hidden; 39 | } 40 | 41 | .speed-bar { 42 | width: 100%; 43 | background: #373b44; /* fallback for old browsers */ 44 | background: -webkit-linear-gradient( 45 | to bottom, 46 | #4286f4, 47 | #373b44 48 | ); /* Chrome 10-25, Safari 5.1-6 */ 49 | background: linear-gradient( 50 | to bottom, 51 | #4286f4, 52 | #373b44 53 | ); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */ 54 | 55 | cursor: grab; 56 | text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2); 57 | display: flex; 58 | align-items: center; 59 | justify-content: center; 60 | padding: 2px; 61 | color: white; 62 | height: 16.3%; 63 | } 64 | -------------------------------------------------------------------------------- /29-Countdown-Timer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Countdown Timer - JavaScript30 by Ayush Gupta 6 | 11 | 12 | 17 | 23 | 29 | 30 | 31 | 32 |
    33 |
    #29
    34 |
    of JavaScript30
    35 |
    36 |
    37 |
    38 |
    39 | 40 | 41 | 42 | 43 | 44 |
    45 | 46 |
    47 |
    48 |
    49 |

    50 |

    51 |
    52 |
    53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /29-Countdown-Timer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "29-countdown-clock", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /29-Countdown-Timer/src/index.js: -------------------------------------------------------------------------------- 1 | let countdown; 2 | const timerDisplay = document.querySelector(".display__time-left"); 3 | const endTime = document.querySelector(".display__end-time"); 4 | const buttons = document.querySelectorAll("[data-time]"); 5 | 6 | function timer(seconds) { 7 | // clear any existing timers 8 | clearInterval(countdown); 9 | 10 | const now = Date.now(); 11 | const then = now + seconds * 1000; 12 | displayTimeLeft(seconds); 13 | displayEndTime(then); 14 | 15 | countdown = setInterval(() => { 16 | const secondsLeft = Math.round((then - Date.now()) / 1000); 17 | // check if we should stop it! 18 | if (secondsLeft < 0) { 19 | clearInterval(countdown); 20 | return; 21 | } 22 | // display it 23 | displayTimeLeft(secondsLeft); 24 | }, 1000); 25 | } 26 | 27 | function displayTimeLeft(seconds) { 28 | const minutes = Math.floor(seconds / 60); 29 | const remainderSeconds = seconds % 60; 30 | const display = `${minutes}:${ 31 | remainderSeconds < 10 ? "0" : "" 32 | }${remainderSeconds}`; 33 | document.title = display; 34 | timerDisplay.textContent = display; 35 | } 36 | 37 | function displayEndTime(timestamp) { 38 | const end = new Date(timestamp); 39 | const hour = end.getHours(); 40 | const adjustedHour = hour > 12 ? hour - 12 : hour; 41 | const minutes = end.getMinutes(); 42 | endTime.textContent = `Be Back At ${adjustedHour}:${ 43 | minutes < 10 ? "0" : "" 44 | }${minutes}`; 45 | } 46 | 47 | function startTimer() { 48 | const seconds = parseInt(this.dataset.time); 49 | timer(seconds); 50 | } 51 | 52 | buttons.forEach(button => button.addEventListener("click", startTimer)); 53 | document.customForm.addEventListener("submit", function(e) { 54 | e.preventDefault(); 55 | const mins = this.minutes.value; 56 | console.log(mins); 57 | timer(mins * 60); 58 | this.reset(); 59 | }); 60 | -------------------------------------------------------------------------------- /29-Countdown-Timer/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 10px; 4 | background: #2B2C34; 5 | background: url('../../assets/shattered-island.gif') 6 | } 7 | 8 | *, 9 | *:before, 10 | *:after { 11 | box-sizing: inherit; 12 | } 13 | 14 | body { 15 | margin: 0; 16 | text-align: center; 17 | font-family: "Inconsolata", monospace; 18 | } 19 | 20 | .display__time-left { 21 | font-weight: 100; 22 | font-size: 20rem; 23 | margin: 0; 24 | color: white; 25 | text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.05); 26 | } 27 | 28 | .timer { 29 | display: flex; 30 | min-height: 100vh; 31 | flex-direction: column; 32 | } 33 | 34 | .timer__controls { 35 | display: flex; 36 | } 37 | 38 | .timer__controls > * { 39 | flex: 1; 40 | } 41 | 42 | .timer__controls form { 43 | flex: 1; 44 | display: flex; 45 | } 46 | 47 | .timer__controls input { 48 | flex: 1; 49 | border: 0; 50 | padding: 2rem; 51 | } 52 | 53 | .timer__button { 54 | /* background: none; */ 55 | border: 0; 56 | cursor: pointer; 57 | color: white; 58 | font-size: 2rem; 59 | text-transform: uppercase; 60 | background: rgba(0, 0, 0, 0.1); 61 | border-bottom: 3px solid rgba(0, 0, 0, 0.2); 62 | border-right: 1px solid rgba(0, 0, 0, 0.2); 63 | padding: 1rem; 64 | font-family: "Inconsolata", monospace; 65 | } 66 | 67 | .timer__button:hover, 68 | .timer__button:focus { 69 | background: rgba(0, 0, 0, 0.2); 70 | outline: 0; 71 | } 72 | 73 | .color:nth-child(5n+1) { 74 | background-color: #7fb069; 75 | } 76 | .color:nth-child(5n+2) { 77 | background-color: #8963BA; 78 | } 79 | .color:nth-child(5n+3) { 80 | background-color: #E6AA68; 81 | } 82 | .color:nth-child(5n+4) { 83 | background-color: #DF6553; 84 | } 85 | .color:nth-child(5n+5) { 86 | background-color: #1FCBFF; 87 | } 88 | 89 | input { 90 | background-color: rgb(214, 214, 214); 91 | color: #000; 92 | } 93 | 94 | .display { 95 | flex: 1; 96 | display: flex; 97 | flex-direction: column; 98 | align-items: center; 99 | justify-content: center; 100 | } 101 | 102 | .display__end-time { 103 | font-size: 4rem; 104 | color: white; 105 | } 106 | 107 | #project-tag { 108 | position: absolute; 109 | bottom: 0; 110 | right: 0; 111 | background-color: yellow; 112 | border: 1px solid transparent; 113 | /* border-radius: 0px 3px 3px 0px; */ 114 | border-top-left-radius: 3px; 115 | color: black; 116 | font-weight: bolder; 117 | font-family: monospace; 118 | font-size: medium; 119 | height: 6vh; 120 | display: flex; 121 | flex-direction: column; 122 | justify-content: center; 123 | align-items: center; 124 | padding: 5px 15px; 125 | transition-timing-function: linear; 126 | box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); 127 | } -------------------------------------------------------------------------------- /30-Whack-A-Mole/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Whack A Mole! - JavaScript30 by Ayush Gupta 6 | 11 | 12 | 13 | 18 | 24 | 30 | 31 | 32 | 33 |
    34 |
    #30
    35 |
    of JavaScript30
    36 |
    37 |
    38 |

    Whack-a-mole!

    39 |

    Your Score - 0

    40 |
    41 | Start Game 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 | 68 | 69 | -------------------------------------------------------------------------------- /30-Whack-A-Mole/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "30-whack-a-mole", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /30-Whack-A-Mole/src/index.js: -------------------------------------------------------------------------------- 1 | const holes = document.querySelectorAll(".hole"); 2 | const scoreBoard = document.querySelector(".score"); 3 | const moles = document.querySelectorAll(".mole"); 4 | 5 | let lastHole; 6 | let timeUp = false; 7 | let score = 0; 8 | 9 | function randomTime(min, max) { 10 | return Math.round(Math.random() * (max - min) + min); 11 | } 12 | 13 | function randomHole(holes) { 14 | const idx = Math.floor(Math.random() * holes.length); 15 | const hole = holes[idx]; 16 | if (hole === lastHole) { 17 | console.log("Ah nah thats the same one bud"); 18 | return randomHole(holes); 19 | } 20 | lastHole = hole; 21 | return hole; 22 | } 23 | 24 | function peep() { 25 | const time = randomTime(200, 1000); 26 | const hole = randomHole(holes); 27 | hole.classList.add("up"); 28 | setTimeout(() => { 29 | hole.classList.remove("up"); 30 | if (!timeUp) peep(); 31 | }, time); 32 | } 33 | 34 | function startGame() { 35 | document.querySelector('.btn').textContent = 'Start Game' 36 | scoreBoard.textContent = 0; 37 | timeUp = false; 38 | score = 0; 39 | peep(); 40 | setTimeout(() => {timeUp = true; 41 | document.querySelector('.btn').textContent = 'Game Over, Start again!' 42 | }, 10000); 43 | } 44 | 45 | function bonk(e) { 46 | if (!e.isTrusted) return; // cheater! 47 | score++; 48 | this.parentNode.classList.remove("up"); 49 | scoreBoard.textContent = score; 50 | } 51 | 52 | moles.forEach(mole => mole.addEventListener("click", bonk)); 53 | -------------------------------------------------------------------------------- /30-Whack-A-Mole/src/styles.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 10px; 4 | background-color: #ffc600; 5 | background-image: url("data:image/svg+xml,%3Csvg width='42' height='44' viewBox='0 0 42 44' xmlns='http://www.w3.org/2000/svg'%3E%3Cg id='Page-1' fill='none' fill-rule='evenodd'%3E%3Cg id='brick-wall' fill='%23282828' fill-opacity='0.06'%3E%3Cpath d='M0 0h42v44H0V0zm1 1h40v20H1V1zM0 23h20v20H0V23zm22 0h20v20H22V23z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); 6 | } 7 | 8 | *, 9 | *:before, 10 | *:after { 11 | box-sizing: inherit; 12 | } 13 | 14 | body { 15 | padding: 0; 16 | margin: 0; 17 | font-family: 'Amatic SC', cursive; 18 | } 19 | 20 | h1 { 21 | text-align: center; 22 | font-size: 10rem; 23 | line-height: 1; 24 | margin-bottom: 20px; 25 | margin-top: 20px; 26 | } 27 | 28 | h3 { 29 | text-align: center; 30 | font-size: 4rem; 31 | line-height: 1; 32 | } 33 | 34 | .btn-container { 35 | display: flex; 36 | justify-content: center; 37 | } 38 | 39 | .btn { 40 | top: 0; 41 | left: 0; 42 | transition: all 0.15s linear 0s; 43 | position: relative; 44 | display: inline-block; 45 | min-width: 15vw; 46 | height: 6vh; 47 | padding: 15px 25px; 48 | background-color: #754c03; 49 | text-transform: uppercase; 50 | color: #fff; 51 | font-family: sans-serif; 52 | font-size: large; 53 | font-weight: 600; 54 | letter-spacing: 1px; 55 | box-shadow: -6px 6px 0 #c79c00; 56 | text-decoration: none; 57 | text-align: center; 58 | } 59 | .btn:hover { 60 | top: 3px; 61 | left: -3px; 62 | box-shadow: -3px 3px 0 #404040; 63 | } 64 | .btn:hover::after { 65 | top: 1px; 66 | left: -2px; 67 | width: 4px; 68 | height: 4px; 69 | } 70 | .btn:hover::before { 71 | bottom: -2px; 72 | right: 1px; 73 | width: 4px; 74 | height: 4px; 75 | } 76 | .btn::after { 77 | transition: all 0.15s linear 0s; 78 | content: ''; 79 | position: absolute; 80 | top: 2px; 81 | left: -4px; 82 | width: 8px; 83 | height: 8px; 84 | background-color: #404040; 85 | transform: rotate(45deg); 86 | z-index: -1; 87 | } 88 | .btn::before { 89 | transition: all 0.15s linear 0s; 90 | content: ''; 91 | position: absolute; 92 | bottom: -4px; 93 | right: 2px; 94 | width: 8px; 95 | height: 8px; 96 | background-color: #404040; 97 | transform: rotate(45deg); 98 | z-index: -1; 99 | } 100 | 101 | a.btn { 102 | position: relative; 103 | } 104 | 105 | a:active.btn { 106 | top: 6px; 107 | left: -6px; 108 | box-shadow: none; 109 | } 110 | a:active.btn:before { 111 | bottom: 1px; 112 | right: 1px; 113 | } 114 | a:active.btn:after { 115 | top: 1px; 116 | left: 1px; 117 | } 118 | 119 | .score { 120 | background: rgba(255, 255, 255, 0.2); 121 | padding: 0 3rem; 122 | line-height: 1; 123 | border-radius: 1rem; 124 | font-weight: bold; 125 | font-size: 5rem; 126 | } 127 | 128 | .game { 129 | width: 600px; 130 | height: 400px; 131 | display: flex; 132 | flex-wrap: wrap; 133 | margin: 0 auto; 134 | } 135 | 136 | .hole { 137 | flex: 1 0 33.33%; 138 | overflow: hidden; 139 | position: relative; 140 | } 141 | 142 | .hole:after { 143 | display: block; 144 | background: url('../../assets/dirt.svg') bottom center no-repeat; 145 | background-size: contain; 146 | content: ''; 147 | width: 100%; 148 | height: 70px; 149 | position: absolute; 150 | z-index: 2; 151 | bottom: -30px; 152 | } 153 | 154 | .mole { 155 | background: url('../../assets/mole.svg') bottom center no-repeat; 156 | background-size: 60%; 157 | position: absolute; 158 | top: 100%; 159 | width: 100%; 160 | height: 100%; 161 | transition: all 0.4s; 162 | cursor: grabbing; 163 | } 164 | 165 | .hole.up .mole { 166 | top: 0; 167 | } 168 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ayush Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript 30 Challenge by WesBos 2 | 3 | Participating in and completing 30 day [Vanilla JS challenge (#JavaScript30)](https://javascript30.com/) by [WesBos](https://wesbos.com/). 4 | 5 | ## Todo Challenges 6 | 7 | - [x] 🥁 [JS Drum Kit](https://javascript30.ayushgupta.tech/01-JS-Drum-Kit/index.html) 8 | - [x] 🕒 [JS and CSS Clock](https://javascript30.ayushgupta.tech/02-JS-CSS-Clock/index.html) 9 | - [x] 🖼 [CSS Variables](https://javascript30.ayushgupta.tech/03-CSS-Variables/index.html) 10 | - [x] 🕺🏻 [Array Cardio Day 1](https://javascript30.ayushgupta.tech/04-Array-Cardio-1/index.html) 11 | - [x] 💪🏻 [Flex Panel Gallery](https://javascript30.ayushgupta.tech/04-Array-Cardio-1/index.html) 12 | - [x] ⌨ [Type Ahead](https://javascript30.ayushgupta.tech/06-Type-Ahead/index.html) 13 | - [x] 💃🏻 [Array Cardio Day 2](https://javascript30.ayushgupta.tech/07-Array-Cardio-2/index.html) 14 | - [x] 🌈 [Fun with HTML5 Canvas](https://javascript30.ayushgupta.tech/08-HTML5-Canvas/index.html) 15 | - [x] 🛠 [Dev Tools Domination](https://javascript30.ayushgupta.tech/09-Dev-Tools/index.html) 16 | - [x] ✔ [Hold Shift and Check Checkboxes](https://javascript30.ayushgupta.tech/10-Multiple-Check-Shift/index.html) 17 | - [x] 📽 [Custom Video Player](https://javascript30.ayushgupta.tech/11-Custom-Video-Player/index.html) 18 | - [x] 🎊 [Key Sequence Detection](https://javascript30.ayushgupta.tech/12-Key-Sequence-Detection/index.html) 19 | - [x] 🤜🏻 [Slide in on Scroll](https://javascript30.ayushgupta.tech/13-Slide-In-On-Scroll/index.html) 20 | - [x] 📋 [JavaScript References vs Copying](https://javascript30.ayushgupta.tech/14-JS-Reference-Vs-Copy/index.html) 21 | - [x] 🏪 [LocalStorage](https://javascript30.ayushgupta.tech/15-Localstorage/index.html) 22 | - [x] 🐁 [Mouse Move Shadow](https://javascript30.ayushgupta.tech/16-Mousemove-Shadow/index.html) 23 | - [x] 🗃 [Sort Without Articles](https://javascript30.ayushgupta.tech/17-Sort-Without-Articles/index.html) 24 | - [x] ➕ [Adding Up Times with Reduce](https://javascript30.ayushgupta.tech/18-Add-Time-With-Reduce/index.html) 25 | - [x] 📷 [Webcam Fun](https://javascript30.ayushgupta.tech/19-Webcam-Fun/index.html) 26 | - [x] 🗣 [Speech Detection](https://javascript30.ayushgupta.tech/20-Speech-Recognition/index.html) 27 | - [x] 📌 [Geolocation](https://javascript30.ayushgupta.tech/21-Geolocation/index.html) 28 | - [x] 🔗 [Follow Along Link Highlighter](https://javascript30.ayushgupta.tech/22-Follow-Along-Link/index.html) 29 | - [x] 💬 [Speech Synthesis](https://javascript30.ayushgupta.tech/23-Speech-Synthesis/index.html) 30 | - [x] 🍡 [Sticky Nav](https://javascript30.ayushgupta.tech/24-Sticky-Nav/index.html) 31 | - [x] 💭 [Event Capture, Propogation, Bubbling and Once](https://javascript30.ayushgupta.tech/25-EventCapture-Propogation-Bubbling/index.html) 32 | - [x] 🏃🏻‍♂️ [Stripe Follow Along Nav](https://javascript30.ayushgupta.tech/26-Stripe-Nav/index.html) 33 | - [x] 🎚 [Click and Drag](https://javascript30.ayushgupta.tech/27-Click-Drag-Scroll/index.html) 34 | - [x] 📹 [Video Speed Controller](https://javascript30.ayushgupta.tech/28-Video-Speed-Controller/index.html) 35 | - [x] ⏱ [Countdown Timer](https://javascript30.ayushgupta.tech/29-Countdown-Timer/index.html) 36 | - [x] 🎮 [Whack A Mole](https://javascript30.ayushgupta.tech/30-Whack-A-Mole/index.html) 37 | 38 | ## Add-Ons 39 | 40 | I have mentioned below the add-ons I added in some of the JavaScript30 projects for fun. 41 | 42 | - ✨ * - All projects 43 | 44 | Updated design of all projects because designing is therapeutic. 45 | 46 | - 🥁 #1 - JS Drum Kit 47 | 48 | Added touch & click event handling on keys 49 | 50 | - 🕒 #2 - JS and CSS Clock 51 | 52 | Changed size of clock hands & added a pivot in center 53 | 54 | - 🖼 #3 - CSS Variables 55 | 56 | Added border-radius controller 57 | 58 | - 📽 #11 - Custom Video Player 59 | 60 | Added FullScreen button 61 | 62 | - 🎊 #12 - Key Sequence Detection 63 | 64 | Added confetti options 65 | 66 | - 🏪 #15 - LocalStorage 67 | 68 | Added Check All, Uncheck All, Delete All buttons. 69 | 70 | - 📷 #19 - Webcam fun 71 | 72 | Added mirror image for video. 73 | 74 | - 🎮 #30 - Whack A Mole 75 | 76 | Notify user about game over. -------------------------------------------------------------------------------- /assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /assets/asteroids.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/asteroids.jpg -------------------------------------------------------------------------------- /assets/celebration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/celebration.png -------------------------------------------------------------------------------- /assets/fancy-pants.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/fancy-pants.jpg -------------------------------------------------------------------------------- /assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/favicon-16x16.png -------------------------------------------------------------------------------- /assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/favicon-32x32.png -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/favicon.ico -------------------------------------------------------------------------------- /assets/green-goblin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/green-goblin.png -------------------------------------------------------------------------------- /assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript30 - Ayush Gupta", 3 | "short_name": "JavaScript30", 4 | "description": "30 day vanilla JS coding challenge by WesBos", 5 | "icons": [ 6 | { 7 | "src": "android-chrome-192x192.png", 8 | "sizes": "192x192", 9 | "type": "image/png" 10 | }, 11 | { 12 | "src": "android-chrome-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png" 15 | } 16 | ], 17 | "start_url": "/?source=pwa", 18 | "theme_color": "#000000de", 19 | "background_color": "#000000de", 20 | "display": "standalone" 21 | } 22 | -------------------------------------------------------------------------------- /assets/ocean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/ocean.jpg -------------------------------------------------------------------------------- /assets/og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/og.png -------------------------------------------------------------------------------- /assets/plaid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/plaid.jpg -------------------------------------------------------------------------------- /assets/shattered-island.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/shattered-island.gif -------------------------------------------------------------------------------- /assets/special-delivery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/special-delivery.jpg -------------------------------------------------------------------------------- /assets/wild-sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gupta-ji6/JavaScript30/8e6c6c46dd24b61fccf350828cb5e7fcdbd4bdaf/assets/wild-sea.png -------------------------------------------------------------------------------- /common.css: -------------------------------------------------------------------------------- 1 | .project-tag { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | background-color: yellow; 6 | border: 1px solid transparent; 7 | /* border-radius: 0px 3px 3px 0px; */ 8 | border-bottom-right-radius: 3px; 9 | color: black; 10 | font-weight: bolder; 11 | font-family: monospace; 12 | font-size: medium; 13 | height: 5vh; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | padding: 5px 15px; 19 | transition-timing-function: linear; 20 | box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); 21 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JavaScript30", 3 | "version": "1.0.0", 4 | "description": "Repo for managing JavaScript30 challenge by @wesbos", 5 | "main": "README.md", 6 | "scripts": { 7 | "start": "parcel index.html --open", 8 | "build": "parcel build index.html" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@babel/core": "7.2.0", 13 | "parcel-bundler": "^1.6.1" 14 | }, 15 | "keywords": [] 16 | } 17 | -------------------------------------------------------------------------------- /sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | https://javascript30.ayushgupta.tech/ 12 | 2020-08-26T13:44:36+00:00 13 | 1.00 14 | 15 | 16 | https://javascript30.ayushgupta.tech/01-js-drum-kit/ 17 | 2020-08-26T13:44:36+00:00 18 | 0.80 19 | 20 | 21 | https://javascript30.ayushgupta.tech/02-js-css-clock/ 22 | 2020-08-26T13:44:36+00:00 23 | 0.80 24 | 25 | 26 | https://javascript30.ayushgupta.tech/03-css-variables/ 27 | 2020-08-26T13:44:36+00:00 28 | 0.80 29 | 30 | 31 | https://javascript30.ayushgupta.tech/04-array-cardio-1/ 32 | 2020-08-26T13:44:36+00:00 33 | 0.80 34 | 35 | 36 | https://javascript30.ayushgupta.tech/05-flex-gallery/ 37 | 2020-08-26T13:44:36+00:00 38 | 0.80 39 | 40 | 41 | https://javascript30.ayushgupta.tech/06-type-ahead/ 42 | 2020-08-26T13:44:36+00:00 43 | 0.80 44 | 45 | 46 | https://javascript30.ayushgupta.tech/07-array-cardio-2/ 47 | 2020-08-26T13:44:36+00:00 48 | 0.80 49 | 50 | 51 | https://javascript30.ayushgupta.tech/08-html5-canvas/ 52 | 2020-08-26T13:44:36+00:00 53 | 0.80 54 | 55 | 56 | https://javascript30.ayushgupta.tech/09-dev-tools/ 57 | 2020-08-26T13:44:36+00:00 58 | 0.80 59 | 60 | 61 | https://javascript30.ayushgupta.tech/10-multiple-check-shift/ 62 | 2020-08-26T13:44:36+00:00 63 | 0.80 64 | 65 | 66 | https://javascript30.ayushgupta.tech/11-custom-video-player/ 67 | 2020-08-26T13:44:36+00:00 68 | 0.80 69 | 70 | 71 | https://javascript30.ayushgupta.tech/12-key-sequence-detection/ 72 | 2020-08-26T13:44:36+00:00 73 | 0.80 74 | 75 | 76 | https://javascript30.ayushgupta.tech/13-slide-in-on-scroll/ 77 | 2020-08-26T13:44:36+00:00 78 | 0.80 79 | 80 | 81 | https://javascript30.ayushgupta.tech/14-js-reference-vs-copy/ 82 | 2020-08-26T13:44:36+00:00 83 | 0.80 84 | 85 | 86 | https://javascript30.ayushgupta.tech/15-localstorage/ 87 | 2020-08-26T13:44:36+00:00 88 | 0.80 89 | 90 | 91 | https://javascript30.ayushgupta.tech/16-mousemove-shadow/ 92 | 2020-08-26T13:44:36+00:00 93 | 0.80 94 | 95 | 96 | https://javascript30.ayushgupta.tech/17-sort-without-articles/ 97 | 2020-08-26T13:44:36+00:00 98 | 0.80 99 | 100 | 101 | https://javascript30.ayushgupta.tech/18-add-time-with-reduce/ 102 | 2020-08-26T13:44:36+00:00 103 | 0.80 104 | 105 | 106 | https://javascript30.ayushgupta.tech/19-webcam-fun/ 107 | 2020-08-26T13:44:36+00:00 108 | 0.80 109 | 110 | 111 | https://javascript30.ayushgupta.tech/20-speech-recognition/ 112 | 2020-08-26T13:44:36+00:00 113 | 0.80 114 | 115 | 116 | https://javascript30.ayushgupta.tech/21-geolocation/ 117 | 2020-08-26T13:44:36+00:00 118 | 0.80 119 | 120 | 121 | https://javascript30.ayushgupta.tech/22-follow-along-link/ 122 | 2020-08-26T13:44:36+00:00 123 | 0.80 124 | 125 | 126 | https://javascript30.ayushgupta.tech/23-speech-synthesis/ 127 | 2020-08-26T13:44:36+00:00 128 | 0.80 129 | 130 | 131 | https://javascript30.ayushgupta.tech/24-sticky-nav/ 132 | 2020-08-26T13:44:36+00:00 133 | 0.80 134 | 135 | 136 | https://javascript30.ayushgupta.tech/25-eventcapture-propogation-bubbling/ 137 | 2020-08-26T13:44:36+00:00 138 | 0.80 139 | 140 | 141 | https://javascript30.ayushgupta.tech/26-stripe-nav/ 142 | 2020-08-26T13:44:36+00:00 143 | 0.80 144 | 145 | 146 | https://javascript30.ayushgupta.tech/27-click-drag-scroll/ 147 | 2020-08-26T13:44:36+00:00 148 | 0.80 149 | 150 | 151 | https://javascript30.ayushgupta.tech/28-video-speed-controller/ 152 | 2020-08-26T13:44:36+00:00 153 | 0.80 154 | 155 | 156 | https://javascript30.ayushgupta.tech/29-countdown-timer/ 157 | 2020-08-26T13:44:36+00:00 158 | 0.80 159 | 160 | 161 | https://javascript30.ayushgupta.tech/30-whack-a-mole/ 162 | 2020-08-26T13:44:36+00:00 163 | 0.80 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-color: #ebecf0; 3 | --text-color: #000000de; 4 | } 5 | 6 | body { 7 | background: var(--bg-color); 8 | margin: 30px 0px 0px 0px; 9 | display: flex; 10 | align-items: center; 11 | flex-direction: column; 12 | width: 100vw; 13 | } 14 | 15 | .title { 16 | font-family: "Molle", cursive; 17 | font-size: 50px; 18 | margin-bottom: 0; 19 | letter-spacing: 1.2px; 20 | color: var(--text-color); 21 | } 22 | 23 | .subtitle { 24 | font-family: monospace; 25 | color: var(--text-color); 26 | text-align: center; 27 | } 28 | 29 | .github-buttons { 30 | display: flex; 31 | justify-content: space-evenly; 32 | margin-bottom: 50px; 33 | flex-wrap: wrap; 34 | min-width: 30vh; 35 | flex-grow: 2; 36 | } 37 | 38 | .btn { 39 | width: 20vw !important; 40 | } 41 | 42 | .grid-container { 43 | display: grid; 44 | align-items: center; 45 | grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); 46 | grid-gap: 50px; 47 | width: 80vw; 48 | visibility: hidden; 49 | } 50 | 51 | .grid-container > * { 52 | visibility: visible; 53 | transition: opacity 150ms linear 100ms, transform 150ms ease-in-out 100ms; 54 | } 55 | 56 | .grid-container:hover > * { 57 | opacity: 0.5; 58 | transform: scale(0.9); 59 | } 60 | 61 | .grid-container > *:hover { 62 | opacity: 1; 63 | transform: scale(1.02); 64 | transition-delay: 0ms, 0ms; 65 | } 66 | 67 | .items { 68 | min-height: 25vh; 69 | box-shadow: -5px -5px 20px 0 #ffffff, 5px 5px 20px 0 #aeaec0; 70 | border: 1px solid transparent; 71 | border-radius: 5px; 72 | transition: all 0.2s ease-in-out; 73 | background: #e3e6ecde; 74 | cursor: pointer; 75 | display: flex; 76 | flex-direction: column; 77 | align-items: center; 78 | justify-content: center; 79 | font-size: 20px; 80 | font-family: monospace; 81 | text-align: center; 82 | padding: 5px; 83 | } 84 | 85 | .items:hover { 86 | box-shadow: inset -2px -2px 5px #ffffff, inset 2px 2px 5px #d1d9e6; 87 | /* border-top: 2px solid #00000031; */ 88 | /* border-left: 2px solid #00000031; */ 89 | transition: all 0.2s ease-in-out; 90 | font-size: 22px; 91 | font-weight: bolder; 92 | } 93 | 94 | a { 95 | text-decoration: none; 96 | color: black; 97 | } 98 | 99 | .footer { 100 | height: 12vh; 101 | width: 100vw; 102 | margin-top: 5vh; 103 | display: flex; 104 | justify-content: center; 105 | align-items: center; 106 | box-shadow: inset -3px -3px 7px #000000, inset 3px 3px 7px var(--bg-color); 107 | background-color: rgb(34, 34, 34); 108 | color: var(--bg-color); 109 | font-family: monospace; 110 | font-size: 16px; 111 | } 112 | 113 | .footer > a { 114 | color: var(--bg-color); 115 | font-weight: bolder; 116 | } 117 | --------------------------------------------------------------------------------