├── Calculator ├── index.css ├── index.html └── index.js ├── Day-Night-Toggle-Switch ├── index.css ├── index.html └── index.js ├── Download-Button ├── index.css ├── index.html └── index.js ├── Draggable-list ├── index.css ├── index.html └── index.js ├── Eye-Follow-Cursor ├── index.css ├── index.html └── index.js ├── IMDB ├── index.css ├── index.html └── index.js ├── Pokemon-Viewer ├── index.css ├── index.html └── index.js ├── Profile-Viewer ├── index.css ├── index.html └── index.js ├── README.md ├── Rock-Paper-Scissor-Lizard-Spock ├── assets │ ├── lizard.png │ ├── paper.png │ ├── rock.png │ ├── scissor.png │ └── spock.png ├── index.css ├── index.html └── index.js ├── Roman-To-Numeral-Calculator ├── index.css ├── index.html └── index.js ├── Text-Typing-Effect ├── index.css ├── index.html └── index.js ├── Tic-Tac-Toe ├── index.css ├── index.html └── index.js ├── Todo-list ├── index.css ├── index.html └── index.js ├── Whack-A-Mole ├── assets │ ├── dirt.png │ └── mole.png ├── index.css ├── index.html └── index.js └── Word-Falling-Effect ├── index.css └── index.html /Calculator/index.css: -------------------------------------------------------------------------------- 1 | #calculator { 2 | width: 300px; 3 | margin: 0 auto; 4 | padding: 10px; 5 | background: #eee; 6 | box-shadow: 0 0 3px; 7 | } 8 | 9 | /* Calculate Area Style */ 10 | #calc-area { 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | flex-wrap: wrap; 15 | } 16 | 17 | #calc-area > span, 18 | #calc-area > textarea { 19 | display: inline-flex; 20 | flex: 100%; 21 | justify-content: center; 22 | margin-bottom: 20px; 23 | } 24 | 25 | #calc-area > textarea { 26 | border: 2px solid #eee; 27 | background: beige; 28 | box-shadow: 0 0 3px; 29 | min-height: 60px; 30 | resize: none; 31 | font-size: 1.8em; 32 | letter-spacing: 2.5px; 33 | } 34 | 35 | #calc-area > span { 36 | font-size: 2em; 37 | } 38 | 39 | /* Button area style */ 40 | #button-area { 41 | padding: 10px 0; 42 | } 43 | 44 | .button-group { 45 | display: flex; 46 | align-items: center; 47 | justify-content: center; 48 | } 49 | 50 | .button-group > span { 51 | display: inline-flex; 52 | flex: 1 1; 53 | padding: 15px 10px; 54 | justify-content: center; 55 | align-items: center; 56 | background: #ff9800; 57 | margin: 4px; 58 | border-radius: 50%; 59 | color: #fff; 60 | font-size: 2em; 61 | box-shadow: 0 0 3px #968585; 62 | transition: all 0.2s ease; 63 | opacity: 0.8; 64 | cursor: pointer; 65 | } 66 | 67 | .button-group > span.calc { 68 | flex: 2.5; 69 | border-radius: 7px; 70 | background: #f44336; 71 | } 72 | 73 | .button-group > span:hover { 74 | opacity: 1; 75 | } 76 | -------------------------------------------------------------------------------- /Calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 |
11 |
12 | Calculator 13 | 14 |
15 |
16 |
17 | % 18 | C 19 | < 20 | / 21 |
22 |
23 | 7 24 | 8 25 | 9 26 | * 27 |
28 |
29 | 4 30 | 5 31 | 6 32 | - 33 |
34 |
35 | 1 36 | 2 37 | 3 38 | + 39 |
40 | 41 |
42 | 0 43 | . 44 | = 45 |
46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Calculator/index.js: -------------------------------------------------------------------------------- 1 | //Where inputs are displayed 2 | const calcArea = document.querySelector("textarea"); 3 | 4 | //operators 5 | const oprList = ["+", "-", "*", "/", "%", "."]; 6 | 7 | //Add input 8 | const addNums = text => { 9 | let { value } = calcArea; 10 | 11 | //Rules to add dot 12 | const ruleA = value.length === 0 && text === "."; 13 | 14 | //Add only if both rules apply 15 | if (!ruleA) { 16 | calcArea.value += text; 17 | } 18 | }; 19 | 20 | //Add operators 21 | const addOpr = text => { 22 | const { value } = calcArea; 23 | const lastCharacter = value[value.length - 1]; 24 | 25 | //Don't add repeated operators and initially without numbers 26 | if (lastCharacter !== text) { 27 | if (value.length > 0) { 28 | calcArea.value += text; 29 | } 30 | } 31 | 32 | //If last character is operator then replace it with new operator 33 | if (oprList.includes(lastCharacter)) { 34 | calcArea.value = value.substr(0, value.length - 1) + text; 35 | } 36 | }; 37 | 38 | //Delete inputs on backspace 39 | const del = () => { 40 | const { value } = calcArea; 41 | if (value.length > 0) { 42 | calcArea.value = value.substr(0, value.length - 1); 43 | } 44 | }; 45 | 46 | //Clear whole area 47 | const clear = () => { 48 | calcArea.value = ""; 49 | }; 50 | 51 | //Perform calculation 52 | const calc = () => { 53 | const { value } = calcArea; 54 | const result = eval(value); 55 | 56 | if (!isNaN(result)) { 57 | calcArea.value = result; 58 | } else { 59 | alert("Wrong expression, Please check your input"); 60 | } 61 | }; 62 | 63 | //Add event listeners to the button 64 | document.querySelectorAll(".button-group > span").forEach(e => { 65 | e.addEventListener("click", f => { 66 | const { classList, innerText } = f.target; 67 | 68 | if (classList.contains("num")) { 69 | //Number buttons clicked including . 70 | addNums(innerText); 71 | } else if (classList.contains("opr")) { 72 | //Opertor buttons clicked 73 | addOpr(innerText); 74 | } else if (classList.contains("calc")) { 75 | //Equal button clicked 76 | calc(); 77 | } else if (classList.contains("delete")) { 78 | //Backspace button clicked 79 | del(); 80 | } else if (classList.contains("clear")) { 81 | //Clear button clicked 82 | clear(); 83 | } 84 | }); 85 | }); 86 | 87 | //Add key events 88 | document.addEventListener("keydown", e => { 89 | switch (e.key) { 90 | case "1": 91 | case "2": 92 | case "3": 93 | case "4": 94 | case "5": 95 | case "6": 96 | case "7": 97 | case "8": 98 | case "9": 99 | case "0": 100 | case ".": 101 | addNums(e.key); 102 | break; 103 | case "/": 104 | case "*": 105 | case "+": 106 | case "-": 107 | case "%": 108 | addOpr(e.key); 109 | break; 110 | case "Enter": 111 | calc(); 112 | break; 113 | case "Backspace": 114 | del(); 115 | break; 116 | case "c": 117 | clear(); 118 | default: 119 | break; 120 | } 121 | }); 122 | -------------------------------------------------------------------------------- /Day-Night-Toggle-Switch/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .sun-moon { 6 | position: relative; 7 | width: 100px; 8 | height: 56px; 9 | padding: 5px; 10 | border-radius: 45px; 11 | border: 3px solid #1a237e; 12 | background-color: #3f51b5; 13 | overflow: hidden; 14 | transition: all 1s cubic-bezier(0.6, -0.28, 0.735, 0.045); 15 | } 16 | 17 | .sun-moon input { 18 | position: absolute; 19 | width: 100%; 20 | height: 100%; 21 | left: 0; 22 | top: 0; 23 | margin: 0; 24 | opacity: 0; 25 | z-index: 1; 26 | cursor: pointer; 27 | } 28 | 29 | .circle { 30 | border-radius: 50%; 31 | display: inline-block; 32 | position: absolute; 33 | } 34 | 35 | .small { 36 | width: 30px; 37 | height: 30px; 38 | background: #3f51b5; 39 | left: 20px; 40 | top: 3px; 41 | transition: all 1s cubic-bezier(0.6, -0.28, 0.735, 0.045); 42 | } 43 | 44 | .large { 45 | width: 40px; 46 | height: 40px; 47 | background: #fff; 48 | border: 3px solid #fff; 49 | top: 50%; 50 | transform: translateY(-50%); 51 | left: 7px; 52 | transition: all 1s cubic-bezier(0.6, -0.28, 0.735, 0.045); 53 | } 54 | 55 | .move { 56 | background-color: #fff; 57 | border-color: #f3909a; 58 | } 59 | 60 | .move .large { 61 | left: 50px; 62 | background: yellow; 63 | border-color: orange; 64 | } 65 | 66 | .move .small { 67 | left: 60px; 68 | top: 50px; 69 | background-color: #fff; 70 | } 71 | -------------------------------------------------------------------------------- /Day-Night-Toggle-Switch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Day Night Toggle Switch 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Day-Night-Toggle-Switch/index.js: -------------------------------------------------------------------------------- 1 | const switchBox = document.querySelector(".sun-moon"); 2 | 3 | document.querySelector("input").addEventListener("change", (e) => { 4 | const { checked } = e.target; 5 | if (checked) { 6 | switchBox.classList.add("move"); 7 | } else { 8 | switchBox.classList.remove("move"); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /Download-Button/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .wrapper { 6 | position: relative; 7 | width: 100px; 8 | height: 100px; 9 | border: 1px solid #000; 10 | overflow: hidden; 11 | } 12 | 13 | .loader { 14 | position: absolute; 15 | width: 100%; 16 | height: 100%; 17 | top: -100%; 18 | left: 0; 19 | background: red; 20 | border-radius: 40px; 21 | transition: all 1s cubic-bezier(0.17, 0.52, 0.83, 0.67) 0.35s; 22 | } 23 | 24 | .move .loader { 25 | top: 0; 26 | border-radius: 0; 27 | } 28 | 29 | .icon { 30 | position: absolute; 31 | width: 100%; 32 | height: 100%; 33 | z-index: 1; 34 | background: transparent; 35 | top: 0; 36 | left: 0; 37 | } 38 | 39 | .icon > span { 40 | position: absolute; 41 | width: 4px; 42 | background: green; 43 | transform: translate(-50%, -50%); 44 | } 45 | 46 | .icon > span:nth-child(2) { 47 | height: 25px; 48 | top: 50%; 49 | left: 50%; 50 | transition: top 0.3s ease; 51 | } 52 | 53 | .icon > span:nth-child(1) { 54 | height: 17px; 55 | top: 57%; 56 | left: 45%; 57 | transform: translate(-50%, -50%) rotateZ(-45deg); 58 | } 59 | 60 | .icon > span:nth-child(3) { 61 | height: 17px; 62 | top: 57%; 63 | left: 55%; 64 | transform: translate(-50%, -50%) rotateZ(45deg); 65 | } 66 | 67 | @keyframes pumpLeft { 68 | 40% { 69 | transform: translate(-50%, -50%) rotateZ(105deg); 70 | } 71 | 85% { 72 | transform: translate(-50%, -50%) rotateZ(90deg); 73 | opacity: 0; 74 | } 75 | 100% { 76 | opacity: 0; 77 | } 78 | } 79 | 80 | @keyframes pumpRight { 81 | 40% { 82 | transform: translate(-50%, -50%) rotateZ(-105deg); 83 | } 84 | 85% { 85 | transform: translate(-50%, -50%) rotateZ(-90deg); 86 | } 87 | 100% { 88 | opacity: 0; 89 | } 90 | } 91 | 92 | @keyframes pullDown { 93 | 22% { 94 | top: 13%; 95 | } 96 | 100% { 97 | top: 165%; 98 | } 99 | } 100 | 101 | /* cubic-bezier(0.17, 0.49, 0.53, 0.8) */ 102 | .move .icon > span:nth-child(2) { 103 | animation: pullDown 1.8s cubic-bezier(0.17, 0.52, 0.83, 0.67); 104 | } 105 | 106 | .move .icon > span:nth-child(1) { 107 | animation: pumpRight 0.5s ease forwards; 108 | } 109 | 110 | .move .icon > span:nth-child(3) { 111 | animation: pumpLeft 0.5s ease forwards; 112 | } 113 | -------------------------------------------------------------------------------- /Download-Button/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Download Button Animation 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /Download-Button/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Download-Button/index.js -------------------------------------------------------------------------------- /Draggable-list/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .container { 6 | background-color: #333; 7 | padding: 1rem; 8 | margin-top: 1rem; 9 | } 10 | 11 | .draggable { 12 | padding: 1rem; 13 | background-color: white; 14 | border: 1px solid black; 15 | cursor: move; 16 | } 17 | 18 | .draggable.dragging { 19 | opacity: 0.5; 20 | } 21 | 22 | /* Background Styles Only */ 23 | 24 | @import url("https://fonts.googleapis.com/css?family=Raleway"); 25 | 26 | * { 27 | font-family: Raleway; 28 | } 29 | 30 | .side-links { 31 | position: absolute; 32 | top: 15px; 33 | right: 15px; 34 | } 35 | 36 | .side-link { 37 | display: flex; 38 | align-items: center; 39 | justify-content: center; 40 | text-decoration: none; 41 | margin-bottom: 10px; 42 | color: white; 43 | width: 180px; 44 | padding: 10px 0; 45 | border-radius: 10px; 46 | } 47 | 48 | .side-link-youtube { 49 | background-color: red; 50 | } 51 | 52 | .side-link-twitter { 53 | background-color: #1da1f2; 54 | } 55 | 56 | .side-link-github { 57 | background-color: #6e5494; 58 | } 59 | 60 | .side-link-text { 61 | margin-left: 10px; 62 | font-size: 18px; 63 | } 64 | 65 | .side-link-icon { 66 | color: white; 67 | font-size: 30px; 68 | } 69 | -------------------------------------------------------------------------------- /Draggable-list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Draggable list 7 | 8 | 9 | 10 | 11 |
12 |

1

13 |

2

14 |
15 |
16 |

3

17 |

4

18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /Draggable-list/index.js: -------------------------------------------------------------------------------- 1 | const draggables = document.querySelectorAll(".draggable"); 2 | const containers = document.querySelectorAll(".container"); 3 | 4 | draggables.forEach((draggable) => { 5 | draggable.addEventListener("dragstart", () => { 6 | draggable.classList.add("dragging"); 7 | }); 8 | 9 | draggable.addEventListener("dragend", () => { 10 | draggable.classList.remove("dragging"); 11 | }); 12 | }); 13 | 14 | containers.forEach((container) => { 15 | container.addEventListener("dragover", (e) => { 16 | e.preventDefault(); 17 | const afterElement = getDragAfterElement(container, e.clientY); 18 | const draggable = document.querySelector(".dragging"); 19 | if (afterElement == null) { 20 | container.appendChild(draggable); 21 | } else { 22 | container.insertBefore(draggable, afterElement); 23 | } 24 | }); 25 | }); 26 | 27 | function getDragAfterElement(container, y) { 28 | const draggableElements = [ 29 | ...container.querySelectorAll(".draggable:not(.dragging)"), 30 | ]; 31 | 32 | return draggableElements.reduce( 33 | (closest, child) => { 34 | const box = child.getBoundingClientRect(); 35 | const offset = y - box.top - box.height / 2; 36 | if (offset < 0 && offset > closest.offset) { 37 | return { offset: offset, element: child }; 38 | } else { 39 | return closest; 40 | } 41 | }, 42 | { offset: Number.NEGATIVE_INFINITY } 43 | ).element; 44 | } 45 | -------------------------------------------------------------------------------- /Eye-Follow-Cursor/index.css: -------------------------------------------------------------------------------- 1 | main { 2 | height: 100vh; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | /* Wrapper */ 9 | .eyes { 10 | width: 100px; 11 | height: 100px; 12 | border-radius: 50%; 13 | margin: 5px; 14 | background: #ffeb3b; 15 | box-shadow: 0 0 3px; 16 | position: relative; 17 | overflow: hidden; 18 | } 19 | 20 | /* Eye */ 21 | .eye-retina { 22 | display: inline-block; 23 | width: 50%; 24 | height: 50%; 25 | background: red; 26 | border-radius: 50%; 27 | position: absolute; 28 | top: 50%; 29 | left: 50%; 30 | transform: translate(-50%, -50%); 31 | } 32 | 33 | /* lashes */ 34 | .eye-lash { 35 | position: absolute; 36 | height: 50%; 37 | background: orange; 38 | width: 100%; 39 | z-index: 1; 40 | } 41 | 42 | .up { 43 | top: -50%; 44 | animation: blinkbottom 10s linear infinite; 45 | } 46 | 47 | .down { 48 | bottom: -50%; 49 | animation: blinktop 10s linear infinite; 50 | } 51 | 52 | @keyframes blinkbottom { 53 | 0% { 54 | top: -50%; 55 | } 56 | 5% { 57 | top: 0; 58 | } 59 | 10% { 60 | top: -50%; 61 | } 62 | } 63 | 64 | @keyframes blinktop { 65 | 0% { 66 | bottom: -50%; 67 | } 68 | 5% { 69 | bottom: 0; 70 | } 71 | 10% { 72 | bottom: -50%; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Eye-Follow-Cursor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Eye Follow Cursor 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 | 20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Eye-Follow-Cursor/index.js: -------------------------------------------------------------------------------- 1 | //Eyes 2 | const retina = document.querySelectorAll(".eye-retina"); 3 | 4 | window.addEventListener("mousemove", (e) => { 5 | e = e || window.event; 6 | 7 | //Position of cursor in pixel 8 | const { pageX, pageY } = e; 9 | 10 | //Available area of window 11 | const { innerWidth, innerHeight } = window; 12 | 13 | //Cursor left position in percentage 14 | let left = (pageX / innerWidth) * 100; 15 | 16 | //Cursor top position in percentage 17 | let top = (pageY / innerHeight) * 100; 18 | 19 | //Prevent the eye from getting hidden at the left and right end. 20 | left = left < 25 ? 25 : left; 21 | left = left > 75 ? 75 : left; 22 | 23 | //Prevent the eye from getting hidden at the top and bottom end. 24 | top = top < 25 ? 25 : top; 25 | top = top > 75 ? 75 : top; 26 | 27 | //Move the eye 28 | retina.forEach((f) => { 29 | //If the cursor is in center of both the eyes the keep the eye in center 30 | f.style.left = `${left > 45 && left < 55 ? 50 : left}%`; 31 | f.style.top = `${top > 45 && top < 55 ? 50 : top}%`; 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /IMDB/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: aqua; 7 | } 8 | 9 | #search-area { 10 | text-align: center; 11 | padding-top: 50px; 12 | } 13 | 14 | #search-area > input { 15 | padding: 20px; 16 | font-size: 1.2em; 17 | border: none; 18 | box-shadow: 0px 0px 3px #000; 19 | } 20 | 21 | #search-area > button { 22 | padding: 10px; 23 | margin-left: 30px; 24 | } 25 | 26 | #list-area { 27 | display: flex; 28 | flex-wrap: wrap; 29 | justify-content: space-between; 30 | align-items: center; 31 | } 32 | 33 | .lists { 34 | flex: 25%; 35 | max-width: 25%; 36 | padding: 15px; 37 | overflow: hidden; 38 | } 39 | 40 | .lists > img { 41 | width: 100%; 42 | max-height: 350px; 43 | } 44 | 45 | .lists > p { 46 | margin: 0; 47 | padding: 10px 10px; 48 | background: #e3f2fd; 49 | font-size: 1.1em; 50 | line-height: 1.5em; 51 | } 52 | -------------------------------------------------------------------------------- /IMDB/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IMDB Movie App 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /IMDB/index.js: -------------------------------------------------------------------------------- 1 | const listArea = document.querySelector("#list-area"); 2 | const searchBox = document.querySelector(".searchBox"); 3 | 4 | const getMoviesTitlesList = async (query) => { 5 | showMessage("loading"); 6 | try { 7 | const response = await fetch( 8 | `https://imdb8.p.rapidapi.com/title/auto-complete?q=${query}`, 9 | { 10 | method: "GET", 11 | headers: { 12 | "x-rapidapi-host": "imdb8.p.rapidapi.com", 13 | "x-rapidapi-key": 14 | "1ea0728d75msh4481c9246eff589p1e591djsnef03398ab0f0", 15 | }, 16 | } 17 | ); 18 | 19 | const data = await response.json(); 20 | return data; 21 | } catch (e) { 22 | showMessage(e); 23 | } 24 | }; 25 | 26 | const clearList = () => { 27 | listArea.innerHTML = ""; 28 | }; 29 | 30 | const showMessage = (msg) => { 31 | clearList(); 32 | const elm = document.createElement("p"); 33 | elm.className = "errorMessage"; 34 | elm.innerText = msg; 35 | listArea.append(elm); 36 | }; 37 | 38 | const generateList = (list) => { 39 | const mapped = list.map( 40 | (e) => `
41 | ${e.i ? `${e.l}` : ""} 42 |

${e.l}

43 |
` 44 | ); 45 | clearList(); 46 | listArea.innerHTML = mapped.join(""); 47 | }; 48 | 49 | const search = async () => { 50 | const { value } = searchBox; 51 | const { d } = await getMoviesTitlesList(value); 52 | generateList(d); 53 | }; 54 | 55 | const searchOnEnter = (e) => { 56 | const { key } = e; 57 | if (key === "Enter") { 58 | e.preventDefault(); 59 | search(); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /Pokemon-Viewer/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | main { 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | flex-wrap: wrap; 10 | } 11 | 12 | .list { 13 | flex: 0 0 25%; 14 | width: 25%; 15 | padding: 0 15px; 16 | margin: 15px 0; 17 | } 18 | 19 | .list > div { 20 | padding: 15px 0; 21 | text-align: center; 22 | box-shadow: 0 1px 3px #a5a2a2; 23 | } 24 | 25 | .list img { 26 | max-width: 10em; 27 | } 28 | 29 | .pagination > button { 30 | margin: 0 15px; 31 | } 32 | -------------------------------------------------------------------------------- /Pokemon-Viewer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Pokemon-Viewer/index.js: -------------------------------------------------------------------------------- 1 | const pokeContainer = document.getElementById("pokemon-container"); 2 | 3 | const pageConfig = { 4 | start: 0, 5 | limit: 28, 6 | }; 7 | 8 | const emptyContainer = () => { 9 | pokeContainer.innerHTML = ""; 10 | }; 11 | 12 | const startLoading = () => { 13 | emptyContainer(); 14 | pokeContainer.innerHTML = `

Loading....

`; 15 | }; 16 | 17 | const stopLoading = () => { 18 | emptyContainer(); 19 | }; 20 | 21 | const throwError = ({ message }) => { 22 | emptyContainer(); 23 | pokeContainer.innerHTML = `

${message}

`; 24 | }; 25 | 26 | const fetchURL = async (url) => { 27 | startLoading(); 28 | try { 29 | const response = await fetch(url); 30 | const result = await response.json(); 31 | return result; 32 | } catch (e) { 33 | throwError(e); 34 | } finally { 35 | stopLoading(); 36 | } 37 | }; 38 | 39 | const getPokemonList = async (start, limit) => { 40 | const list = await fetchURL( 41 | `https://pokeapi.co/api/v2/pokemon/?limit=${limit}&offset=${start}` 42 | ); 43 | 44 | const details = []; 45 | const { results } = list; 46 | for (let i = 0; i < results.length; i++) { 47 | const x = await fetchURL(results[i].url); 48 | details.push(x); 49 | } 50 | 51 | return details; 52 | }; 53 | 54 | const generateList = async () => { 55 | const { start, limit } = pageConfig; 56 | const pokemonListWithStats = await getPokemonList(start, limit); 57 | 58 | const mappedList = pokemonListWithStats.reduce((a, b) => { 59 | const { id, name, types, abilities } = b; 60 | 61 | const str = `
62 |
63 | ${name} 64 |
65 |

Id: ${id}

66 |

Name: ${name}

67 |

Types: ${types.reduce((a, b) => { 68 | const { type } = b; 69 | const { name } = type; 70 | return `${a} ${name}`; 71 | }, "")}

72 |

Abilities: ${abilities.reduce((a, b) => { 73 | const { ability } = b; 74 | const { name } = ability; 75 | return `${a} ${name}`; 76 | }, "")}

77 |
78 |
79 |
`; 80 | return `${a} ${str}`; 81 | }, ""); 82 | 83 | // Pagination 84 | const pagination = document.createElement("div"); 85 | pagination.classList.add("pagination"); 86 | const nextButton = document.createElement("button"); 87 | nextButton.innerHTML = "Next"; 88 | nextButton.addEventListener("click", () => { 89 | navigate("next"); 90 | }); 91 | 92 | const prevButton = document.createElement("button"); 93 | prevButton.innerHTML = "Prev"; 94 | prevButton.addEventListener("click", () => { 95 | navigate("prev"); 96 | }); 97 | pagination.appendChild(prevButton); 98 | pagination.appendChild(nextButton); 99 | 100 | pokeContainer.innerHTML = mappedList; 101 | pokeContainer.appendChild(pagination); 102 | }; 103 | 104 | const navigate = (type) => { 105 | let { start, limit } = pageConfig; 106 | if (type === "next") { 107 | start = start + limit; 108 | pageConfig.start = start; 109 | generateList(); 110 | } else { 111 | start = start - limit; 112 | pageConfig.start = start < 0 ? 0 : start; 113 | generateList(); 114 | } 115 | }; 116 | 117 | generateList(); 118 | -------------------------------------------------------------------------------- /Profile-Viewer/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | /* wrapper */ 6 | .profile { 7 | display: flex; 8 | align-items: center; 9 | flex-wrap: wrap; 10 | max-width: 80%; 11 | margin: 20px auto; 12 | } 13 | 14 | /* User circle */ 15 | .user-bio { 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | position: relative; 20 | width: 400px; 21 | height: 400px; 22 | } 23 | 24 | /* Circle */ 25 | .circle { 26 | display: flex; 27 | justify-content: center; 28 | align-items: center; 29 | text-align: center; 30 | position: absolute; 31 | top: 50%; 32 | left: 50%; 33 | border-radius: 50%; 34 | border: 1px solid; 35 | backface-visibility: hidden; 36 | transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), 37 | background 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); 38 | box-shadow: 0 0 8px #000; 39 | } 40 | 41 | .front { 42 | background: #3f51b5; 43 | width: 320px; 44 | height: 320px; 45 | margin: -160px; 46 | font-size: 2.5em; 47 | color: #fff; 48 | padding: 10px; 49 | cursor: pointer; 50 | } 51 | 52 | .front:hover { 53 | background: #232844; 54 | } 55 | 56 | /* When profile is open */ 57 | .open .front { 58 | transform: rotateY(180deg); 59 | } 60 | 61 | .back { 62 | width: 400px; 63 | height: 400px; 64 | background: #ff5722; 65 | margin: -200px; 66 | font-size: 1.4em; 67 | color: #000; 68 | padding: 20px; 69 | /* Shrink and rotate initially */ 70 | transform: scale(0.7972973) rotateY(180deg); 71 | } 72 | 73 | /* Scale it to normal */ 74 | .open .back { 75 | transform: scale(1) rotateY(0); 76 | } 77 | 78 | /* Icons */ 79 | .social-icons { 80 | display: inline-flex; 81 | justify-content: space-evenly; 82 | align-items: center; 83 | flex: 1; 84 | } 85 | 86 | .icons { 87 | display: inline-flex; 88 | width: 120px; 89 | height: 120px; 90 | border-radius: 50%; 91 | background: #8e24aa; 92 | justify-content: center; 93 | align-items: center; 94 | font-size: 3em; 95 | color: #fff; 96 | text-decoration: none; 97 | transform: scale(0) rotateZ(180deg); 98 | transition: transform 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94); 99 | box-shadow: 0 0 8px #000; 100 | } 101 | 102 | .icons:nth-child(1) { 103 | transition-delay: 0.12s; 104 | } 105 | 106 | .icons:nth-child(2) { 107 | transition-delay: 0.24s; 108 | } 109 | 110 | .icons:nth-child(3) { 111 | transition-delay: 0.36s; 112 | } 113 | 114 | /* Transfrom and show icons */ 115 | .open .icons { 116 | transform: scale(1) rotateZ(0); 117 | } 118 | 119 | /* Close button */ 120 | .close-btn { 121 | flex: 1 1 100%; 122 | display: inline-flex; 123 | align-items: center; 124 | flex-direction: inherit; 125 | } 126 | 127 | .close-btn > span { 128 | display: inline-flex; 129 | width: 50px; 130 | height: 50px; 131 | border-radius: 50%; 132 | background: red; 133 | justify-content: center; 134 | align-items: center; 135 | font-size: 1.8em; 136 | color: #fff; 137 | box-shadow: 0 0 8px #000; 138 | cursor: pointer; 139 | transform: scale(0) rotateZ(360deg); 140 | transition: transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); 141 | } 142 | 143 | /* Transform on open */ 144 | .open .close-btn > span { 145 | transform: scale(1) rotateZ(0); 146 | } 147 | -------------------------------------------------------------------------------- /Profile-Viewer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Profile Viewer 7 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 | Prashant Yadav 27 |
28 | 29 |
30 | Software Developer with 3+ years of experience facilitating 31 | cutting-edge engineering solutions with a wide range of applications 32 | and technology skills 33 |
34 |
35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Profile-Viewer/index.js: -------------------------------------------------------------------------------- 1 | const Front = document.querySelector(".front"); 2 | const Close = document.querySelector(".close-btn > span"); 3 | const Profile = document.querySelector(".profile"); 4 | 5 | //Add open class 6 | Front.addEventListener("click", () => { 7 | profile.classList.add("open"); 8 | }); 9 | 10 | //Remove the class 11 | Close.addEventListener("click", () => { 12 | profile.classList.remove("open"); 13 | }); 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vanilla-js-components 2 | A list of 50 Components created in vanilla JS 3 | -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/assets/lizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Rock-Paper-Scissor-Lizard-Spock/assets/lizard.png -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/assets/paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Rock-Paper-Scissor-Lizard-Spock/assets/paper.png -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/assets/rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Rock-Paper-Scissor-Lizard-Spock/assets/rock.png -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/assets/scissor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Rock-Paper-Scissor-Lizard-Spock/assets/scissor.png -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/assets/spock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Rock-Paper-Scissor-Lizard-Spock/assets/spock.png -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | main { 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | width: 80%; 10 | margin: 0 auto; 11 | flex-wrap: wrap; 12 | } 13 | 14 | /* Score style */ 15 | #result { 16 | flex: 1 100%; 17 | } 18 | 19 | #round-message, 20 | #score { 21 | text-align: center; 22 | } 23 | 24 | #round-message { 25 | font-size: 1.5em; 26 | text-transform: capitalize; 27 | } 28 | 29 | #score { 30 | font-size: 3em; 31 | margin-bottom: 10px; 32 | } 33 | 34 | /* Player style */ 35 | .players { 36 | display: inline-flex; 37 | flex-wrap: wrap; 38 | flex: 1; 39 | padding: 10px 25px; 40 | } 41 | 42 | .selected-option, 43 | .name, 44 | .available-options { 45 | display: inline-flex; 46 | flex: 1 100%; 47 | padding: 15px 0; 48 | } 49 | 50 | .selected-option, 51 | .name { 52 | justify-content: center; 53 | } 54 | 55 | .name { 56 | font-size: 1.8em; 57 | color: #f44336; 58 | font-weight: 600; 59 | } 60 | 61 | /* Options Style */ 62 | .available-options { 63 | justify-content: space-between; 64 | } 65 | 66 | .option { 67 | display: inline-flex; 68 | justify-content: center; 69 | align-items: center; 70 | width: 75px; 71 | height: 75px; 72 | padding: 10px; 73 | border-radius: 50%; 74 | border: 1px solid #f44336; 75 | box-shadow: 0 0 3px; 76 | cursor: pointer; 77 | } 78 | 79 | .option.active { 80 | border-color: blue; 81 | } 82 | 83 | .option:hover > img { 84 | transform: scale(1.1); 85 | } 86 | 87 | .option > img { 88 | width: 70%; 89 | transition: all 0.2s ease; 90 | } 91 | 92 | .selected-option > .option { 93 | width: 110px; 94 | height: 110px; 95 | } 96 | 97 | /* Rotate the scissor of second player */ 98 | #player2 .option > img[alt="Scissor"] { 99 | transform: rotate(180deg); 100 | } 101 | 102 | #player2 .option:hover > img[alt="Scissor"] { 103 | transform: rotate(180deg) scale(1.1); 104 | } 105 | 106 | #player2 .option { 107 | cursor: not-allowed; 108 | background-color: #80cbc4; 109 | } 110 | 111 | /* Reset button */ 112 | .reset { 113 | display: inline-flex; 114 | flex: 1 100%; 115 | justify-content: center; 116 | margin-top: 20px; 117 | } 118 | 119 | .reset > span { 120 | font-size: 1.8em; 121 | cursor: pointer; 122 | border: 1px solid red; 123 | padding: 10px 15px; 124 | background-color: #f44336; 125 | box-shadow: 0 0 3px; 126 | color: #fff; 127 | transition: all 0.2s ease; 128 | } 129 | 130 | .reset > span:hover { 131 | color: #000; 132 | } 133 | -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Rock, Paper, Scissor, Lizard, Spock Game 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 0 15 | : 16 | 0 17 |
18 |

Choose your option

19 |
20 | 21 | 22 |
23 | Player1 24 |
25 | 26 |
27 |
28 | 29 | Lizard 30 | 31 | 32 | Paper 33 | 34 | 35 | Rock 36 | 37 | 38 | Scissor 39 | 40 | 41 | Spock 42 | 43 |
44 |
45 | 46 | 47 |
48 | Bot 49 |
50 | 51 |
52 |
53 | 54 | Lizard 55 | 56 | 57 | Paper 58 | 59 | 60 | Rock 61 | 62 | 63 | Scissor 64 | 65 | 66 | Spock 67 | 68 |
69 |
70 | 71 | 72 | Reset 73 |
74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Rock-Paper-Scissor-Lizard-Spock/index.js: -------------------------------------------------------------------------------- 1 | //Order in which options are available 2 | const arr = [ 3 | { 4 | image: "lizard.png", 5 | name: "Lizard", 6 | }, 7 | { 8 | image: "paper.png", 9 | name: "Paper", 10 | }, 11 | { 12 | image: "rock.png", 13 | name: "Rock", 14 | }, 15 | { 16 | image: "scissor.png", 17 | name: "Scissor", 18 | }, 19 | { 20 | image: "spock.png", 21 | name: "Spock", 22 | }, 23 | ]; 24 | 25 | //Rule of who has win over whom 26 | const rule = { 27 | Lizard: ["Spock", "Paper"], 28 | 29 | Paper: ["Rock", "Spock"], 30 | 31 | Rock: ["Lizard", "Scissor"], 32 | 33 | Scissor: ["Paper", "Lizard"], 34 | 35 | Spock: ["Scissor", "Rock"], 36 | }; 37 | 38 | //Folder in which images are stored 39 | const imageFolderPath = "assets"; 40 | 41 | //All the options of player 1 42 | const player1Options = document.querySelectorAll( 43 | "#player1 .available-options .option" 44 | ); 45 | 46 | //All the options of bot 47 | const botOptions = document.querySelectorAll( 48 | "#player2 .available-options .option" 49 | ); 50 | 51 | //Where selected option of player 1 will be shown 52 | const playerShowArea = document.querySelector( 53 | "#player1 .selected-option .option" 54 | ); 55 | 56 | //Where selected option of bot will be shown 57 | const botShowArea = document.querySelector("#player2 .selected-option .option"); 58 | 59 | //Player 1 and bot score 60 | const player1Score = document.querySelector("#player1-score"); 61 | const player2Score = document.querySelector("#player2-score"); 62 | 63 | //Where message will be shown 64 | const roundMessage = document.querySelector("#round-message"); 65 | 66 | player1Options.forEach((e) => { 67 | e.addEventListener("click", () => { 68 | play(e); 69 | }); 70 | }); 71 | 72 | const play = (e) => { 73 | //Get the index of the option selected by player 74 | const player1 = e.getAttribute("data-index"); 75 | 76 | //Number of options available 77 | const length = arr.length; 78 | 79 | //Generate a random number between number of options available for bot 80 | const player2 = Math.floor(Math.random() * length); 81 | 82 | //Show the player1 selected option and highlight it 83 | showPlayerOption(player1, playerShowArea); 84 | highlightSelectedOption(player1, player1Options); 85 | 86 | //Show the bot selected option 87 | showPlayerOption(player2, botShowArea); 88 | highlightSelectedOption(player2, botOptions); 89 | 90 | //Calculate the result 91 | calculateScore(player1, player2); 92 | }; 93 | 94 | //Generate an image element 95 | const generateImgElement = (index) => { 96 | const { image, name } = arr[index]; 97 | const imgElement = document.createElement("img"); 98 | imgElement.src = `${imageFolderPath}/${image}`; 99 | imgElement.alt = name; 100 | imgElement.title = name; 101 | return imgElement; 102 | }; 103 | 104 | //Show selected option 105 | const showPlayerOption = (index, showArea) => { 106 | //Append the generated image to the show area 107 | const imgElement = generateImgElement(index); 108 | showArea.innerHTML = ""; 109 | showArea.append(imgElement); 110 | }; 111 | 112 | const highlightSelectedOption = (index, options) => { 113 | //Remove the active class from all options 114 | options.forEach((e) => { 115 | e.classList.remove("active"); 116 | }); 117 | 118 | //Add the active class to the selected option 119 | options[index].classList.add("active"); 120 | }; 121 | 122 | //Change the score 123 | const addScore = (player) => { 124 | const { innerHTML } = player; 125 | player.innerHTML = Number(innerHTML) + 1; 126 | }; 127 | 128 | const showMessage = (msg) => { 129 | //Show the message 130 | roundMessage.innerHTML = ""; 131 | roundMessage.innerHTML = msg; 132 | }; 133 | 134 | const calculateScore = (player1, player2) => { 135 | //Player 1 choice 136 | const player1Choice = arr[player1].name; 137 | 138 | //Bot choice 139 | const player2Choice = arr[player2].name; 140 | 141 | //Get player 1 selected choice rule 142 | const player1Strength = rule[player1Choice]; 143 | 144 | //Check the case and who wins the round 145 | if (player1Choice === player2Choice) { 146 | showMessage("draw"); 147 | } else if (player1Strength.includes(player2Choice)) { 148 | //Update the score and show message who won the round 149 | addScore(player1Score); 150 | showMessage("player 1 wins"); 151 | } else { 152 | //Update the score and show message who won the round 153 | addScore(player2Score); 154 | showMessage("Bot wins"); 155 | } 156 | }; 157 | 158 | const reset = () => { 159 | botShowArea.innerHTML = ""; 160 | playerShowArea.innerHTML = ""; 161 | roundMessage.innerHTML = "Choose your option"; 162 | player2Score.innerHTML = "0"; 163 | player1Score.innerHTML = "0"; 164 | player1Options.forEach((e) => { 165 | e.classList.remove("active"); 166 | }); 167 | botOptions.forEach((e) => { 168 | e.classList.remove("active"); 169 | }); 170 | }; 171 | 172 | document.querySelector(".reset").addEventListener("click", reset); 173 | -------------------------------------------------------------------------------- /Roman-To-Numeral-Calculator/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .wrapper { 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: stretch; 9 | max-width: 1000px; 10 | margin: 60px auto; 11 | flex-wrap: wrap; 12 | } 13 | 14 | .calc, 15 | .info { 16 | display: inline-flex; 17 | justify-content: center; 18 | align-items: center; 19 | flex-wrap: wrap; 20 | flex: 0 1 48%; 21 | width: 48%; 22 | padding: 25px; 23 | } 24 | 25 | .box { 26 | box-shadow: 0 0 3px #000; 27 | } 28 | 29 | .field-group, 30 | .output { 31 | display: inline-flex; 32 | flex: 1 1 100%; 33 | align-items: center; 34 | justify-content: center; 35 | margin-bottom: 20px; 36 | } 37 | 38 | .output { 39 | border: 1px solid #000; 40 | border-radius: 5px; 41 | background: #eee; 42 | min-height: 100px; 43 | margin: 30px 0; 44 | font-size: 2.2em; 45 | } 46 | 47 | input[type="text"] { 48 | width: 100%; 49 | padding: 10px; 50 | font-size: 2em; 51 | border: 1px solid #000; 52 | margin-bottom: 10px; 53 | } 54 | 55 | input[type="checkbox"] { 56 | width: 20px; 57 | height: 20px; 58 | } 59 | 60 | .btn { 61 | font-size: 1.8em; 62 | cursor: pointer; 63 | border: 1px solid red; 64 | padding: 10px 15px; 65 | background-color: #f44336; 66 | box-shadow: 0 0 3px; 67 | color: #fff; 68 | transition: color 0.2s ease; 69 | } 70 | 71 | .btn:hover { 72 | color: #000; 73 | } 74 | 75 | .rows { 76 | display: inline-flex; 77 | flex: 1 1 100%; 78 | flex-wrap: wrap; 79 | } 80 | 81 | .rows > span { 82 | flex: 1 1 50%; 83 | text-align: center; 84 | font-size: 2em; 85 | } 86 | -------------------------------------------------------------------------------- /Roman-To-Numeral-Calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Roman To Numeral Calculator 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 |

Convert Roman To Integer

15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 | Convert 29 | 30 | 31 |

32 |
33 | 34 | 35 |
36 |
37 | Roman Letter 38 | Integer Value 39 |
40 |
41 | I 42 | 1 43 |
44 |
45 | V 46 | 5 47 |
48 |
49 | X 50 | 10 51 |
52 |
53 | L 54 | 50 55 |
56 |
57 | C 58 | 100 59 |
60 |
61 | D 62 | 500 63 |
64 |
65 | M 66 | 1000 67 |
68 |
69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Roman-To-Numeral-Calculator/index.js: -------------------------------------------------------------------------------- 1 | const heading = document.querySelector("h1"); 2 | const romanToNumeral = document.querySelector("input[type='checkbox']"); 3 | const conversionInput = document.querySelector("input[type='text']"); 4 | const outputArea = document.querySelector(".output"); 5 | const convertButton = document.querySelector(".btn"); 6 | 7 | romanToNumeral.addEventListener("change", (e) => { 8 | const { checked } = e.target; 9 | if (checked) { 10 | heading.innerHTML = "Convert Integer To Roman"; 11 | } else { 12 | heading.innerHTML = "Convert Roman To Integer"; 13 | } 14 | }); 15 | 16 | //Call the appropriate conversion function 17 | const calc = () => { 18 | const { checked } = romanToNumeral; 19 | 20 | if (checked) { 21 | convertIntegerToRoman(); 22 | } else { 23 | convertRomanToInteger(); 24 | } 25 | }; 26 | 27 | //Calculate on convert button click 28 | convertButton.addEventListener("click", () => { 29 | calc(); 30 | }); 31 | 32 | //Calculate when enter is pressed. 33 | window.addEventListener("keypress", (e) => { 34 | if (e.key === "Enter") { 35 | calc(); 36 | } 37 | }); 38 | 39 | //Converts roman numeral to integer 40 | const convertRomanToInteger = () => { 41 | //Regex to validate roman numberal 42 | const romanNumeralRegex = new RegExp( 43 | /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/ 44 | ); 45 | 46 | let { value: roman } = conversionInput; 47 | roman = roman.toUpperCase(); 48 | const regexResult = romanNumeralRegex.test(roman); 49 | 50 | if (!regexResult) { 51 | alert("Please enter a valid roman numeral"); 52 | return false; 53 | } 54 | 55 | //sequence of roman letters 56 | let arr = ["I", "V", "X", "L", "C", "D", "M"]; 57 | 58 | //value of the respective roman letters 59 | let values = { 60 | I: 1, 61 | V: 5, 62 | X: 10, 63 | L: 50, 64 | C: 100, 65 | D: 500, 66 | M: 1000, 67 | }; 68 | 69 | let sum = 0; 70 | 71 | //keep track of the previous index 72 | let prevIndex = 0; 73 | 74 | for (let i = roman.length - 1; i >= 0; i--) { 75 | //if the current letter is having greater index than previous letter then add values 76 | if (arr.indexOf(roman[i]) >= prevIndex) { 77 | sum = sum + values[roman[i]]; 78 | } else { 79 | //if the current letter is having lesser index than previous letter then sub values 80 | sum = sum - values[roman[i]]; 81 | } 82 | 83 | //store the index of the previous roman letters 84 | prevIndex = arr.indexOf(roman[i]); 85 | } 86 | 87 | //Add the result to the output area 88 | outputArea.innerHTML = sum; 89 | }; 90 | 91 | //Converts integer to roman numeral 92 | const convertIntegerToRoman = () => { 93 | //Regex to validate if there are only numbers 94 | const numberRegex = new RegExp(/^\d+$/); 95 | 96 | let { value: num } = conversionInput; 97 | const regexResult = numberRegex.test(num); 98 | 99 | if (!regexResult) { 100 | alert("Please enter a valid integer"); 101 | return false; 102 | } 103 | 104 | if (Number(num) > 4999) { 105 | alert("Out of range. Please enter a integer less than 5000."); 106 | return false; 107 | } 108 | 109 | //Mapping 110 | const mapping = { 111 | 1: "I", 112 | 5: "V", 113 | 10: "X", 114 | 50: "L", 115 | 100: "C", 116 | 500: "D", 117 | 1000: "M", 118 | }; 119 | 120 | let count = 1; 121 | let str = ""; 122 | while (num > 0) { 123 | let last = parseInt(num % 10); 124 | last *= count; 125 | if (last < 10) { 126 | str += lessThan9(last, mapping); 127 | } else { 128 | str = greaterThan9(last, mapping) + str; 129 | } 130 | 131 | count *= 10; 132 | num = parseInt(num / 10); 133 | } 134 | outputArea.innerHTML = str; 135 | }; 136 | 137 | //If the integer is less than one 138 | //Generte the roman numeral 139 | const lessThan9 = (num, obj) => { 140 | if (num === 9) { 141 | return obj[1] + obj[10]; 142 | } else if (num >= 5 && num < 9) { 143 | return obj[5] + obj[1].repeat(num % 5); 144 | } else if (num === 4) { 145 | return obj[1] + obj[5]; 146 | } else { 147 | return obj[1].repeat(num); 148 | } 149 | }; 150 | 151 | //If integer is greater than 9 152 | //Generate the roman numeral 153 | const greaterThan9 = (num, obj) => { 154 | if (num >= 10 && num < 50) { 155 | if (num === 10) { 156 | return obj[10]; 157 | } 158 | 159 | if (num === 40) { 160 | return obj[10] + obj[50]; 161 | } else { 162 | return obj[10].repeat(parseInt(num / 10)); 163 | } 164 | } else if (num >= 50 && num < 100) { 165 | if (num === 50) { 166 | return obj[50]; 167 | } 168 | 169 | if (num === 90) { 170 | return obj[10] + obj[100]; 171 | } else { 172 | return obj[50] + obj[10].repeat(parseInt((num - 50) / 10)); 173 | } 174 | } else if (num >= 100 && num < 500) { 175 | if (num === 100) { 176 | return obj[100]; 177 | } 178 | 179 | if (num === 400) { 180 | return obj[100] + obj[500]; 181 | } else { 182 | return obj[100].repeat(parseInt(num / 100)); 183 | } 184 | } else if (num >= 500 && num < 1000) { 185 | if (num === 500) { 186 | return obj[500]; 187 | } 188 | 189 | if (num === 900) { 190 | return obj[100] + obj[1000]; 191 | } else { 192 | return obj[500] + obj[100].repeat(parseInt(num - 500) / 100); 193 | } 194 | } else if (num >= 1000 && num < 5000) { 195 | if (num === 1000) { 196 | return obj[1000]; 197 | } 198 | 199 | return obj[1000].repeat(parseInt(num / 1000)); 200 | } 201 | }; 202 | -------------------------------------------------------------------------------- /Text-Typing-Effect/index.css: -------------------------------------------------------------------------------- 1 | main { 2 | display: flex; 3 | justify-content: center; 4 | flex-wrap: wrap; 5 | align-items: center; 6 | max-width: 80%; 7 | margin: 0 auto; 8 | } 9 | 10 | /* Text area */ 11 | textarea { 12 | flex: 1 100%; 13 | margin-bottom: 30px; 14 | min-height: 9em; 15 | font-size: 2em; 16 | padding: 10px; 17 | border: 1px solid #607d8b; 18 | box-shadow: 0 0 3px; 19 | } 20 | 21 | /* Button and Speed Wrapper */ 22 | .fields{ 23 | display: inline-flex; 24 | justify-content: space-between; 25 | flex: 1; 26 | align-items: center; 27 | } 28 | 29 | /* Speed Selector wrapper */ 30 | .fields-group{ 31 | display: inline-flex; 32 | align-items: center; 33 | justify-content: space-between; 34 | 35 | } 36 | 37 | /* Speed selector */ 38 | label{ 39 | text-align: center; 40 | font-size: 2em; 41 | margin-right: 20px; 42 | } 43 | 44 | select{ 45 | font-size: 1.8em; 46 | cursor: pointer; 47 | border: 1px solid #8BC34A; 48 | padding: 10px 15px; 49 | background-color: #4CAF50; 50 | box-shadow: 0 0 3px; 51 | color: #fff; 52 | } 53 | 54 | /* Button */ 55 | #start-typing-btn { 56 | font-size: 1.8em; 57 | cursor: pointer; 58 | border: 1px solid red; 59 | padding: 10px 15px; 60 | background-color: #f44336; 61 | box-shadow: 0 0 3px; 62 | color: #fff; 63 | transition: all 0.2s ease; 64 | } 65 | 66 | #start-typing-btn:hover { 67 | color: #000; 68 | } 69 | 70 | /* Typing area */ 71 | #type-area { 72 | flex: 1 100%; 73 | min-height: 3em; 74 | font-size: 2em; 75 | padding: 10px; 76 | border: 1px solid #ff5722; 77 | box-shadow: 0 0 3px; 78 | margin-top: 25px; 79 | } 80 | 81 | /* Cursor */ 82 | #cursor { 83 | display: inline-block; 84 | width: 3px; 85 | height: 0.75em; 86 | background: red; 87 | position: relative; 88 | top: 1px; 89 | left: 6px; 90 | animation: blink 1s ease infinite; 91 | } 92 | 93 | @keyframes blink { 94 | from { 95 | opacity: 0; 96 | } 97 | to { 98 | opacity: 1; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Text-Typing-Effect/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Text Typing Effect 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | 32 |
33 | Type 34 |
35 | 36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Text-Typing-Effect/index.js: -------------------------------------------------------------------------------- 1 | //Type button 2 | const btn = document.querySelector("#start-typing-btn"); 3 | 4 | //Type area 5 | const typeArea = document.querySelector("#text-type"); 6 | 7 | btn.addEventListener("click", () => { 8 | // Text value 9 | const str = document.querySelector("#text").value; 10 | // Speed value 11 | let speed = document.querySelector("#type-speed").value; 12 | 13 | // Set the default speed to 250 14 | speed = speed ? Number(speed) : 250; 15 | 16 | // Empty the type area before starting to type again 17 | typeArea.innerHTML = ""; 18 | 19 | // Start typing; 20 | type(str, speed); 21 | }); 22 | 23 | const type = (str, speed) => { 24 | if (str === "") { 25 | //If we have typed everything then stop typing 26 | //By stopping the timer 27 | clearTimeout(interval); 28 | } else { 29 | //Keep typing each character 30 | var interval = setTimeout(() => { 31 | //Add the next character to the type area 32 | typeArea.innerHTML += str.substr(0, 1); 33 | 34 | //Call the function recursively 35 | //With the remaining text to be typed 36 | type(str.substr(1, str.length), speed); 37 | 38 | }, 1000 - speed); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /Tic-Tac-Toe/index.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 350px; 3 | margin: 0 auto; 4 | } 5 | 6 | .option-selection-area { 7 | display: flex; 8 | justify-content: space-evenly; 9 | align-items: center; 10 | flex-wrap: wrap; 11 | } 12 | 13 | .option-selection-area > h1 { 14 | flex: 1 1 100%; 15 | text-align: center; 16 | font-size: 2em; 17 | } 18 | 19 | .field-group { 20 | display: inline-flex; 21 | align-items: center; 22 | font-size: 3em; 23 | } 24 | 25 | input[type="radio"] { 26 | width: 30px; 27 | height: 30px; 28 | } 29 | 30 | .game-area { 31 | margin-top: 10px; 32 | display: flex; 33 | align-items: center; 34 | justify-content: space-around; 35 | flex-wrap: wrap; 36 | } 37 | 38 | .row { 39 | flex: 0 1 calc(33% - 10px); 40 | border: 1px solid; 41 | width: calc(33% - 10px); 42 | margin-bottom: 10px; 43 | } 44 | 45 | /* Create 1:1 by giving padding-bottom */ 46 | .row > div { 47 | width: 100%; 48 | padding-bottom: 100%; 49 | position: relative; 50 | } 51 | 52 | .row > div > span { 53 | font-size: 8em; 54 | position: absolute; 55 | width: 100%; 56 | height: 100%; 57 | display: inline-flex; 58 | justify-content: center; 59 | align-items: center; 60 | text-transform: uppercase; 61 | } 62 | 63 | .result { 64 | text-align: center; 65 | font-size: 2em; 66 | color: green; 67 | } 68 | -------------------------------------------------------------------------------- /Tic-Tac-Toe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tic Tac Toe 7 | 8 | 9 | 10 |
11 | 12 |
13 |

Choose Your Option

14 |
15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Tic-Tac-Toe/index.js: -------------------------------------------------------------------------------- 1 | //Array to track the board 2 | const board = [ 3 | ["", "", ""], 4 | ["", "", ""], 5 | ["", "", ""], 6 | ]; 7 | 8 | //Options available 9 | const options = document.querySelectorAll("[name='player-option']"); 10 | //Board 11 | const rows = document.querySelectorAll(".row"); 12 | //Result area 13 | const result = document.querySelector(".result"); 14 | 15 | //Players option 16 | let ai = "O"; 17 | let human = "X"; 18 | 19 | //Score to decide the next move of bot 20 | const scores = { 21 | X: 10, 22 | O: -10, 23 | tie: 0, 24 | }; 25 | 26 | //Function to update selected option and setting the score for bot 27 | const updateSelector = (value) => { 28 | if (value === "1") { 29 | human = "X"; 30 | ai = "O"; 31 | } else { 32 | human = "O"; 33 | ai = "X"; 34 | } 35 | 36 | //Update the score based on selector 37 | scores[human] = -10; 38 | scores[ai] = 10; 39 | }; 40 | 41 | //Update player option initally 42 | let start = options[0].value; 43 | updateSelector(start); 44 | 45 | //Update player option on option change 46 | options.forEach((e) => { 47 | e.addEventListener("change", (f) => { 48 | const { value } = f.target; 49 | updateSelector(value); 50 | }); 51 | }); 52 | 53 | //Handle the player click on grid 54 | rows.forEach((e) => { 55 | //Get the grand child span 56 | const span = e.children[0].children[0]; 57 | 58 | e.addEventListener("click", (f) => { 59 | //Get which grid is clicked 60 | const dataRow = +e.getAttribute("data-row"); 61 | const dataColumn = +e.getAttribute("data-column"); 62 | 63 | //If the grid is not marked 64 | if (board[dataRow][dataColumn] === "") { 65 | //Player move 66 | span.innerHTML = human; 67 | board[dataRow][dataColumn] = human; 68 | 69 | //Bot move 70 | const botMove = bestMove(); 71 | 72 | //If bot can make move then update the board 73 | if (botMove) { 74 | board[botMove.i][botMove.j] = ai; 75 | const botPlace = document.querySelector( 76 | `[data-row='${botMove.i}'][data-column='${botMove.j}'] span` 77 | ); 78 | 79 | botPlace.innerHTML = ai; 80 | } 81 | 82 | //Get match's result and show it on the dash board 83 | const outcome = checkWinner(); 84 | if (outcome) { 85 | if (outcome === "tie") { 86 | result.innerHTML = outcome; 87 | } else { 88 | result.innerHTML = `${outcome} wins`; 89 | } 90 | } 91 | } 92 | }); 93 | }); 94 | 95 | //Check all the values are equal 96 | const equals3 = (a, b, c) => { 97 | return a == b && b == c && a != ""; 98 | }; 99 | 100 | //Check match winner 101 | const checkWinner = () => { 102 | let winner = null; 103 | 104 | // horizontal 105 | for (let i = 0; i < 3; i++) { 106 | if (equals3(board[i][0], board[i][1], board[i][2])) { 107 | winner = board[i][0]; 108 | } 109 | } 110 | 111 | // Vertical 112 | for (let i = 0; i < 3; i++) { 113 | if (equals3(board[0][i], board[1][i], board[2][i])) { 114 | winner = board[0][i]; 115 | } 116 | } 117 | 118 | // Diagonal 119 | if (equals3(board[0][0], board[1][1], board[2][2])) { 120 | winner = board[0][0]; 121 | } 122 | if (equals3(board[2][0], board[1][1], board[0][2])) { 123 | winner = board[2][0]; 124 | } 125 | 126 | //Are still moves left 127 | let openSpots = 0; 128 | for (let i = 0; i < 3; i++) { 129 | for (let j = 0; j < 3; j++) { 130 | if (board[i][j] == "") { 131 | openSpots++; 132 | } 133 | } 134 | } 135 | 136 | //Return winner 137 | if (winner == null && openSpots == 0) { 138 | return "tie"; 139 | } else { 140 | return winner; 141 | } 142 | }; 143 | 144 | //Bot move 145 | const bestMove = () => { 146 | // AI to make its turn 147 | let bestScore = -Infinity; 148 | let move; 149 | for (let i = 0; i < 3; i++) { 150 | for (let j = 0; j < 3; j++) { 151 | // Is the spot available? 152 | if (board[i][j] == "") { 153 | board[i][j] = ai; 154 | let score = minimax(board, 0, false); 155 | board[i][j] = ""; 156 | if (score > bestScore) { 157 | bestScore = score; 158 | move = { i, j }; 159 | } 160 | } 161 | } 162 | } 163 | 164 | return move; 165 | }; 166 | 167 | //Calculate where next move should take place 168 | const minimax = (board, depth, isMaximizing) => { 169 | //Check the winner and return the score 170 | let result = checkWinner(); 171 | if (result !== null) { 172 | return scores[result]; 173 | } 174 | 175 | if (isMaximizing) { 176 | let bestScore = -Infinity; 177 | for (let i = 0; i < 3; i++) { 178 | for (let j = 0; j < 3; j++) { 179 | // Is the spot available? 180 | if (board[i][j] == "") { 181 | board[i][j] = ai; 182 | let score = minimax(board, depth + 1, false); 183 | board[i][j] = ""; 184 | bestScore = Math.max(score, bestScore); 185 | } 186 | } 187 | } 188 | return bestScore; 189 | } else { 190 | let bestScore = Infinity; 191 | for (let i = 0; i < 3; i++) { 192 | for (let j = 0; j < 3; j++) { 193 | // Is the spot available? 194 | if (board[i][j] == "") { 195 | board[i][j] = human; 196 | let score = minimax(board, depth + 1, true); 197 | board[i][j] = ""; 198 | bestScore = Math.min(score, bestScore); 199 | } 200 | } 201 | } 202 | return bestScore; 203 | } 204 | }; 205 | -------------------------------------------------------------------------------- /Todo-list/index.css: -------------------------------------------------------------------------------- 1 | main { 2 | max-width: 600px; 3 | margin: 50px auto; 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | } 8 | -------------------------------------------------------------------------------- /Todo-list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Todo app 7 | 8 | 9 | 10 |
11 |
12 | 18 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Todo-list/index.js: -------------------------------------------------------------------------------- 1 | //Prefetch all the elements required 2 | const todoInput = document.querySelector("#todo"); 3 | const addBtn = document.querySelector(".btn"); 4 | const todoList = document.querySelector(".todo-list"); 5 | 6 | //Store list 7 | let list = []; 8 | 9 | //Interface for item 10 | const listInterface = (value) => ({ 11 | text: value, 12 | completed: false, 13 | }); 14 | 15 | //Function to remove the item 16 | const removeTodo = (index) => { 17 | list = list.filter((e, i) => i !== index); 18 | generateList(); 19 | }; 20 | 21 | //Function to toggle item status 22 | const markCompleted = (index, status) => { 23 | list = list.map((e, i) => { 24 | //Change status of the item with index provided 25 | if (i === index) { 26 | e.completed = status; 27 | } 28 | return e; 29 | }); 30 | generateList(); 31 | }; 32 | 33 | //Function to generate the list 34 | const generateList = () => { 35 | todoList.innerHTML = ""; 36 | 37 | const mappedList = list.reduce((a, b, i) => { 38 | const { text, completed } = b; 39 | 40 | //Add each list 41 | a = `${a}
42 | ${text} 43 | X 44 | ${ 47 | completed ? "unmark" : "mark" 48 | } 49 |
`; 50 | 51 | //return 52 | return a; 53 | }, ""); 54 | 55 | todoList.innerHTML = mappedList; 56 | }; 57 | 58 | //Function to add new item to the list 59 | const addItem = () => { 60 | const { value } = todoInput; 61 | if (value === "") { 62 | return false; 63 | } 64 | 65 | list.push(listInterface(value)); // push the new item in list 66 | todoInput.value = ""; // clear the input area 67 | generateList(); //generate the list 68 | }; 69 | 70 | //add item on button click 71 | addBtn.addEventListener("click", () => { 72 | addItem(); 73 | }); 74 | 75 | //add input on enter press 76 | todoInput.addEventListener("keydown", (e) => { 77 | const { code } = e; 78 | if (code === "Enter") { 79 | e.preventDefault(); 80 | addItem(); 81 | } 82 | }); 83 | -------------------------------------------------------------------------------- /Whack-A-Mole/assets/dirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Whack-A-Mole/assets/dirt.png -------------------------------------------------------------------------------- /Whack-A-Mole/assets/mole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/know-prashant/vanilla-js-components/38e6d82f69e2f01b76af2789d0b2b54c256659e4/Whack-A-Mole/assets/mole.png -------------------------------------------------------------------------------- /Whack-A-Mole/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | main { 6 | width: 55%; 7 | margin: 0 auto; 8 | } 9 | 10 | #score-area { 11 | display: flex; 12 | justify-content: space-between; 13 | padding: 0 20px; 14 | font-size: 30px; 15 | } 16 | 17 | #play-area { 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | flex-wrap: wrap; 22 | } 23 | 24 | .ground { 25 | display: inline-flex; 26 | flex: 1 1 25%; 27 | justify-content: center; 28 | align-items: center; 29 | padding: 10px; 30 | } 31 | 32 | .wrapper { 33 | position: relative; 34 | width: 100%; 35 | padding-bottom: 100%; 36 | overflow: hidden; 37 | } 38 | 39 | .dirt, 40 | .mole { 41 | position: absolute; 42 | width: 100%; 43 | height: 100%; 44 | left: 0; 45 | background-size: contain; 46 | background-repeat: no-repeat; 47 | } 48 | 49 | .dirt { 50 | background-image: url("./assets/dirt.png"); 51 | z-index: 1; 52 | background-position: center 113%; 53 | } 54 | 55 | .mole { 56 | background-image: url(./assets/mole.png); 57 | transition: all 0.1s ease; 58 | top: 100%; 59 | background-position: bottom; 60 | background-size: 73%; 61 | } 62 | 63 | .ground.active .mole { 64 | top: 0; 65 | } 66 | 67 | button { 68 | position: relative; 69 | font-size: 14px; 70 | font-weight: 600; 71 | text-align: center; 72 | padding: 0.7em 1.2em; 73 | cursor: pointer; 74 | user-select: none; 75 | display: inline-flex; 76 | align-items: center; 77 | justify-content: center; 78 | height: 46px; 79 | min-width: 96px; 80 | border-radius: 4px; 81 | background-color: #fff; 82 | border: 1px solid; 83 | color: #fff; 84 | -webkit-transition: background 0.2s ease; 85 | -moz-transition: background 0.2s ease; 86 | -o-transition: background 0.2s ease; 87 | transition: background 0.2s ease; 88 | } 89 | 90 | .primary { 91 | background-color: #2fcb53; 92 | border-color: #2fcb53; 93 | color: #fff; 94 | } 95 | 96 | .primary:hover { 97 | background-color: #48dd84; 98 | border-color: #48dd84; 99 | } 100 | -------------------------------------------------------------------------------- /Whack-A-Mole/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 |
11 |
12 | 13 | Score: 0 14 |
15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Whack-A-Mole/index.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", () => { 2 | document.querySelector("button").addEventListener("click", () => { 3 | startGame(); 4 | }); 5 | }); 6 | 7 | const startGame = () => { 8 | const grounds = document.querySelectorAll(".ground"); 9 | const length = grounds.length; 10 | 11 | const score = document.querySelector("#score > span"); 12 | let count = 0; 13 | 14 | grounds.forEach((e) => { 15 | e.addEventListener("click", () => { 16 | //If ground has active class which means it has mole 17 | //So increase the count 18 | if (e.classList.contains("active")) { 19 | count++; 20 | score.innerHTML = count; 21 | } 22 | }); 23 | }); 24 | 25 | var interval = setInterval(() => { 26 | //Generate a random number 27 | const random = Math.floor(Math.random() * length); 28 | 29 | //Remove the active class from every ground 30 | grounds.forEach((e) => { 31 | e.classList.remove("active"); 32 | }); 33 | 34 | //Add the active class to random ground 35 | grounds[random].classList.add("active"); 36 | }, 700); 37 | }; 38 | 39 | const throttle = (func, limit) => { 40 | let lastFunc; 41 | let lastRan; 42 | return function () { 43 | const context = this; 44 | const args = arguments; 45 | if (!lastRan) { 46 | func.apply(context, args); 47 | lastRan = Date.now(); 48 | } else { 49 | clearTimeout(lastFunc); 50 | lastFunc = setTimeout(function () { 51 | if (Date.now() - lastRan >= limit) { 52 | func.apply(context, args); 53 | lastRan = Date.now(); 54 | } 55 | }, limit - (Date.now() - lastRan)); 56 | } 57 | }; 58 | }; 59 | -------------------------------------------------------------------------------- /Word-Falling-Effect/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | overflow: hidden; 3 | background: #000; 4 | color: #fff; 5 | } 6 | 7 | #words-wrapper { 8 | position: absolute; 9 | -webkit-perspective-origin: 50% 50%; 10 | perspective-origin: 50% 50%; 11 | -webkit-perspective: 500px; 12 | perspective: 500px; 13 | width: 500px; 14 | height: 500px; 15 | left: 50%; 16 | top: 50%; 17 | margin-left: -250px; 18 | margin-top: -250px; 19 | } 20 | 21 | .word { 22 | position: absolute; 23 | -webkit-transform-origin: 50% 50%; 24 | transform-origin: 50% 50%; 25 | -webkit-transform: translateZ(1500px); 26 | transform: translateZ(1500px); 27 | -webkit-transition: -webkit-transform 1.9s 28 | cubic-bezier(0.25, 0.46, 0.45, 0.94), 29 | opacity 2.1s cubic-bezier(0.25, 0.46, 0.45, 0.94); 30 | transition: transform 1.9s cubic-bezier(0.25, 0.46, 0.45, 0.94), 31 | opacity 2.1s cubic-bezier(0.25, 0.46, 0.45, 0.94); 32 | } 33 | 34 | .horizontal { 35 | transform: translateZ(1500px) rotate(90deg); 36 | -webkit-transform: translateZ(1500px) rotate(90deg); 37 | } 38 | 39 | .word.show { 40 | opacity: 1; 41 | -webkit-transform: translateZ(0); 42 | transform: translateZ(0); 43 | } 44 | 45 | .word.horizontal.show { 46 | -webkit-transform: translateZ(0) rotate(90deg); 47 | transform: translateZ(0) rotate(90deg); 48 | } 49 | -------------------------------------------------------------------------------- /Word-Falling-Effect/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Word Falling Effect 7 | 8 | 9 | 10 | 11 |
12 | 16 | #100DaysOfCode 17 | 18 | dedication 23 | work 33 | hard work 38 | HTML 48 | CSS 58 | simplicity 69 | 70 | Jazz 75 | 100% 80 | Duo 91 | Message 102 | Minimalism 113 | Music 124 | Stay In 135 | Passion 146 | hi 151 | Hello World 162 | UI 173 | UX 184 | Success 194 | Dribble 205 | Codepen 215 | React 225 | Javascript 235 | Nodejs 245 | Vue 255 | Angular 265 | Software 275 | #codeNewbie 285 | Modern 295 | Curiosity 305 | Perfection 315 | Flexbox 325 | Grid 335 | div 346 | Inspiration 356 | Creative 366 | Color 376 | RGBA 386 | Imagination 396 | Technology 401 | Tweet 411 | #womenWhoCode 421 | WebDev 426 |
427 | 428 | 436 | 437 | 438 | --------------------------------------------------------------------------------