├── 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 |
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 |
15 |
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 |
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 ? `
` : ""}
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 |
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 |
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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | Bot
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
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 |
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 | Select Speed
20 |
21 | 100
22 | 200
23 | 300
24 | 400
25 | 500
26 | 600
27 | 700
28 | 800
29 | 900
30 | 1000
31 |
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 |
23 |
24 |
25 |
26 |
29 |
32 |
35 |
38 |
41 |
44 |
47 |
50 |
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 | Add
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 | Start
13 | Score: 0
14 |
15 |
16 |
17 |
18 |
24 |
30 |
36 |
42 |
48 |
54 |
60 |
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 |
--------------------------------------------------------------------------------