├── LICENSE ├── README.md └── projects ├── age-calculator ├── index.html ├── index.js └── style.css ├── amine-pics-generator ├── index.html ├── index.js ├── spinner.svg └── style.css ├── animated-search-bar ├── index.html ├── index.js └── style.css ├── auto-text-effect-animation ├── index.html ├── index.js └── style.css ├── background-image-scroll-effect ├── bg.jpg ├── index.html ├── index.js └── style.css ├── background-video ├── background-video.mp4 ├── index.html ├── index.js ├── preloader.gif └── styles.css ├── basic-calculator ├── index.html ├── index.js └── style.css ├── blurred-background-popup ├── index.html ├── index.js └── style.css ├── bmi-calculator ├── index.html ├── index.js └── style.css ├── button-ripple-effect ├── index.html ├── index.js └── style.css ├── clock ├── index.html ├── index.js └── style.css ├── counter ├── index.html ├── index.js └── styles.css ├── currency-converter ├── index.html ├── index.js └── style.css ├── dad-jokes-generator ├── index.html ├── index.js └── style.css ├── dark-mode-toggle ├── index.html ├── index.js └── style.css ├── dice-roll-simulator ├── index.html ├── index.js └── style.css ├── digital-clock ├── index.html ├── index.js └── style.css ├── double-landing-page ├── index.html ├── index.js └── style.css ├── drum-kits ├── images │ ├── crash.png │ ├── kick.png │ ├── snare.png │ └── tom.png ├── index.html ├── index.js ├── sounds │ ├── crash.mp3 │ ├── kick.mp3 │ ├── snare.mp3 │ └── tom.mp3 └── style.css ├── emoji-rating ├── index.html ├── index.js └── style.css ├── english-dictionary ├── index.html ├── index.js └── style.css ├── feedback-ui ├── index.html ├── index.js └── style.css ├── heart-trail-animation ├── index.html ├── index.js └── style.css ├── image-search-app ├── index.html ├── index.js └── style.css ├── image-slider ├── index.html ├── index.js └── style.css ├── loading-bar ├── index.html ├── index.js └── style.css ├── loan-calculator ├── index.html ├── index.js └── style.css ├── mini-calendar ├── index.html ├── index.js └── style.css ├── month-calender ├── index.html ├── index.js └── style.css ├── mouse-event ├── index.html ├── index.js └── style.css ├── multiplication-app ├── index.html ├── index.js └── style.css ├── music-player ├── index.html ├── pause.png ├── play.png ├── script.js ├── songs │ ├── song1.m4a │ ├── song2.m4a │ └── song3.m4a └── style.css ├── navbar ├── index.html ├── index.js ├── logo.svg └── styles.css ├── new-year-countdown ├── index.html ├── index.js └── style.css ├── note-app ├── index.html ├── index.js └── style.css ├── photo-gallery ├── index.html ├── index.js ├── spinner.svg └── styles.css ├── pomodoro-timer ├── index.html ├── index.js └── style.css ├── profile-statistics ├── index.html ├── index.js └── style.css ├── q-and-a-section ├── app.js ├── index.html └── styles.css ├── random-color-generator ├── index.html ├── index.js └── style.css ├── random-emoji ├── index.html ├── index.js └── style.css ├── random-password-generator ├── index.html ├── index.js ├── source.txt └── style.css ├── random-photos ├── index.html ├── index.js └── style.css ├── random-quote-generator ├── index.html ├── index.js └── style.css ├── real-time-character-counter ├── index.html ├── index.js └── style.css ├── recipe-book-app ├── index.html ├── index.js └── style.css ├── rock-paper-scissors-game ├── index.html ├── index.js └── style.css ├── rotating-image-gallery ├── index.html ├── index.js └── style.css ├── sidebar ├── index.html ├── index.js ├── logo.svg └── styles.css ├── social-media-selector-menu ├── index.html ├── index.js └── style.css ├── step-progress-bar ├── index.html ├── index.js └── style.css ├── sticky-navbar ├── index.html ├── index.js ├── logo.svg └── style.css ├── stopwatch ├── index.html ├── index.js └── style.css ├── tabs ├── app.js ├── index.html └── styles.css ├── temperature-converter ├── index.html ├── index.js └── style.css ├── testimonial-slider ├── index.html ├── index.js └── style.css ├── tip-calculator ├── index.html ├── index.js └── style.css ├── to-do-list ├── index.html ├── index.js └── style.css ├── video-trailer-popup ├── index.html ├── index.js ├── style.css └── trailer.mp4 ├── weather-app ├── index.html ├── index.js └── style.css └── weight-converter ├── index.html ├── index.js └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sahand Ghavidel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTML CSS JavaScript Projects 2 | 3 | This is the source code of the website: 100 HTML CSS JavaScript Projects 4 |
5 | Visit 100jsprojects.com to preview the projects. 6 | 7 |
8 |
9 |

About

10 |

Hi there! I'm Sahand, a web developer with over a decade of experience. This course, "HTML CSS JavaScript Projects," was created to share my knowledge and experience with you. In this course, you'll learn how to build simple, responsive websites using HTML, CSS, and JavaScript.

11 |

In this course, you'll learn how to install Visual Studio Code and its extensions, and then we'll start from scratch with each project. After finishing HTML, we'll move on to CSS and JavaScript. Building in HTML, CSS, or JavaScript is fine, and this guide will explain HTML, CSS, and JavaScript syntax.

12 |

Each project in this course is started from scratch and finished without using copied code. Then, we'll go over the code together to ensure that everyone understands. This program's exciting project-based curriculum includes building modern, super cool, and responsive websites!

13 |

If you have any questions, please feel free to contact me through my email: codewithsahand@gmail.com

14 | Visit my website 15 |
16 | -------------------------------------------------------------------------------- /projects/age-calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Age Calculator 8 | 9 | 10 | 11 |
12 |

Age Calculator

13 |
14 | 15 | 16 | 17 |

Your age is 21 years old

18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /projects/age-calculator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const birthdayEl = document.getElementById("birthday"); 3 | const resultEl = document.getElementById("result"); 4 | 5 | function calculateAge() { 6 | const birthdayValue = birthdayEl.value; 7 | if (birthdayValue === "") { 8 | alert("Please enter your birthday"); 9 | } else { 10 | const age = getAge(birthdayValue); 11 | resultEl.innerText = `Your age is ${age} ${age > 1 ? "years" : "year"} old`; 12 | } 13 | } 14 | 15 | function getAge(birthdayValue) { 16 | const currentDate = new Date(); 17 | const birthdayDate = new Date(birthdayValue); 18 | let age = currentDate.getFullYear() - birthdayDate.getFullYear(); 19 | const month = currentDate.getMonth() - birthdayDate.getMonth(); 20 | 21 | if ( 22 | month < 0 || 23 | (month === 0 && currentDate.getDate() < birthdayDate.getDate()) 24 | ) { 25 | age--; 26 | } 27 | 28 | return age; 29 | } 30 | 31 | btnEl.addEventListener("click", calculateAge); 32 | -------------------------------------------------------------------------------- /projects/age-calculator/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 20px; 4 | font-family: "Montserrat", sans-serif; 5 | background-color: #f7f7f7; 6 | } 7 | 8 | .container { 9 | background-color: white; 10 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 11 | padding: 20px; 12 | max-width: 600px; 13 | margin: 0 auto; 14 | border-radius: 5px; 15 | margin-top: 50px; 16 | } 17 | 18 | h1 { 19 | font-size: 36px; 20 | text-align: center; 21 | margin-top: 0; 22 | margin-bottom: 20px; 23 | } 24 | 25 | .form { 26 | display: flex; 27 | flex-direction: column; 28 | align-items: center; 29 | } 30 | 31 | label { 32 | font-weight: bold; 33 | margin-bottom: 10px; 34 | } 35 | 36 | input { 37 | padding: 8px; 38 | border: 1px solid #ccc; 39 | border-radius: 5px; 40 | width: 100%; 41 | max-width: 300px; 42 | } 43 | 44 | button { 45 | background-color: #007bff; 46 | color: white; 47 | border: none; 48 | padding: 10px 20px; 49 | border-radius: 5px; 50 | margin-top: 10px; 51 | cursor: pointer; 52 | transition: background-color 0.3s ease; 53 | } 54 | 55 | button:hover { 56 | background-color: #0062cc; 57 | } 58 | 59 | #result { 60 | margin-top: 20px; 61 | font-size: 24px; 62 | font-weight: bold; 63 | } 64 | -------------------------------------------------------------------------------- /projects/amine-pics-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Anime Pics Generator 8 | 9 | 10 | 11 |
12 |

Anime Pics Generator

13 | 14 |
15 | 16 |

Anime Name

17 |
18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/amine-pics-generator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const animeContainerEl = document.querySelector(".anime-container"); 3 | const animeImgEl = document.querySelector(".anime-img"); 4 | const amineNameEl = document.querySelector(".anime-name"); 5 | 6 | btnEl.addEventListener("click", async function () { 7 | try { 8 | btnEl.disabled = true; 9 | btnEl.innerText = "Loading..."; 10 | amineNameEl.innerText = "Updating..."; 11 | animeImgEl.src = "spinner.svg"; 12 | const response = await fetch("https://api.catboys.com/img"); 13 | const data = await response.json(); 14 | btnEl.disabled = false; 15 | btnEl.innerText = "Get Anime"; 16 | animeContainerEl.style.display = "block"; 17 | animeImgEl.src = data.url; 18 | amineNameEl.innerText = data.artist; 19 | } catch (error) { 20 | console.log(error); 21 | btnEl.disabled = false; 22 | btnEl.innerText = "Get Anime"; 23 | amineNameEl.innerText = "An error happened, please try again"; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /projects/amine-pics-generator/spinner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/amine-pics-generator/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | background: linear-gradient(to right, lightblue, yellow); 4 | display: flex; 5 | height: 100vh; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: 'Courier New', Courier, monospace; 9 | } 10 | 11 | .container{ 12 | background: aliceblue; 13 | border-radius: 10px; 14 | box-shadow: 0 10px 20px rgba(0,0,0,0.3); 15 | text-align: center; 16 | padding: 10px; 17 | width: 450px; 18 | margin: 5px; 19 | } 20 | 21 | .btn{ 22 | background-color: green; 23 | color: aliceblue; 24 | padding: 10px 30px; 25 | font-size: 16px; 26 | margin-bottom: 30px; 27 | border-radius: 6px; 28 | cursor: pointer; 29 | 30 | } 31 | 32 | .btn:disabled{ 33 | background-color: gray; 34 | cursor: not-allowed; 35 | } 36 | 37 | .anime-img{ 38 | height: 300px; 39 | width: 300px; 40 | border-radius: 50%; 41 | border: 3px solid green; 42 | } 43 | 44 | .anime-name{ 45 | margin: 20px; 46 | background-color: green; 47 | color: aliceblue; 48 | padding: 10px; 49 | border-radius: 6px; 50 | font-size: 17px; 51 | font-weight: 600; 52 | } 53 | 54 | .anime-container{ 55 | display: none; 56 | } -------------------------------------------------------------------------------- /projects/animated-search-bar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Animated Search Bar 8 | 9 | 10 | 11 |
12 | magnifier 17 | 18 | mic-icon 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/animated-search-bar/index.js: -------------------------------------------------------------------------------- 1 | const searchBarContainerEl = document.querySelector(".search-bar-container"); 2 | 3 | const magnifierEl = document.querySelector(".magnifier"); 4 | 5 | magnifierEl.addEventListener("click", () => { 6 | searchBarContainerEl.classList.toggle("active"); 7 | }); 8 | -------------------------------------------------------------------------------- /projects/animated-search-bar/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: aliceblue; 8 | } 9 | 10 | .search-bar-container { 11 | display: flex; 12 | align-items: center; 13 | background-color: aliceblue; 14 | padding: 5px; 15 | width: 300px; 16 | height: 50px; 17 | border-radius: 50px; 18 | box-shadow: 6px 6px 10px rgba(0, 0, 0, 0.2), 19 | -6px -6px 10px rgba(255, 255, 255, 0.7); 20 | margin: 10px; 21 | position: relative; 22 | transition: width 1.5s; 23 | } 24 | 25 | .magnifier { 26 | width: 25px; 27 | cursor: pointer; 28 | position: absolute; 29 | left: 20px; 30 | } 31 | 32 | .mic-icon { 33 | width: 30px; 34 | position: absolute; 35 | right: 10px; 36 | transition: width 0.4s; 37 | transition-delay: 1s; 38 | } 39 | 40 | .input { 41 | background-color: transparent; 42 | border: none; 43 | margin: 10px 50px; 44 | width: 100%; 45 | outline: none; 46 | color: rgb(100, 100, 100); 47 | transition: width 1s; 48 | transition-delay: 0.5s; 49 | } 50 | 51 | .active.search-bar-container { 52 | width: 50px; 53 | } 54 | 55 | .active .input { 56 | width: 0; 57 | } 58 | 59 | .active .mic-icon { 60 | width: 0; 61 | } 62 | -------------------------------------------------------------------------------- /projects/auto-text-effect-animation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Auto Text Effect Animation 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/auto-text-effect-animation/index.js: -------------------------------------------------------------------------------- 1 | const containerEl = document.querySelector(".container"); 2 | 3 | const careers = ["YouTuber", "Web Developer", "Freelancer", "Instructor"]; 4 | 5 | let careerIndex = 0; 6 | 7 | let characterIndex = 0; 8 | 9 | updateText(); 10 | 11 | function updateText() { 12 | characterIndex++; 13 | containerEl.innerHTML = ` 14 |

I am ${careers[careerIndex].slice(0, 1) === "I" ? "an" : "a"} ${careers[ 15 | careerIndex 16 | ].slice(0, characterIndex)}

17 | `; 18 | 19 | if (characterIndex === careers[careerIndex].length) { 20 | careerIndex++; 21 | characterIndex = 0; 22 | } 23 | 24 | if (careerIndex === careers.length) { 25 | careerIndex = 0; 26 | } 27 | setTimeout(updateText, 400); 28 | } 29 | -------------------------------------------------------------------------------- /projects/auto-text-effect-animation/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap"); 2 | 3 | body { 4 | margin: 0; 5 | display: flex; 6 | justify-content: center; 7 | height: 100vh; 8 | align-items: center; 9 | background-color: salmon; 10 | font-family: "Permanent Marker", cursive; 11 | } 12 | -------------------------------------------------------------------------------- /projects/background-image-scroll-effect/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/background-image-scroll-effect/bg.jpg -------------------------------------------------------------------------------- /projects/background-image-scroll-effect/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Background Image Scroll Effect 8 | 9 | 10 | 11 |
12 |
13 |

Welcome to our website

14 |

15 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 16 | provident veritatis quos dolorum repellendus officia voluptate veniam id 17 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 18 | quisquam? Deleniti, eius. 19 |

20 |

21 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 22 | provident veritatis quos dolorum repellendus officia voluptate veniam id 23 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 24 | quisquam? Deleniti, eius. 25 |

26 |

27 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 28 | provident veritatis quos dolorum repellendus officia voluptate veniam id 29 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 30 | quisquam? Deleniti, eius. 31 |

32 |

33 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 34 | provident veritatis quos dolorum repellendus officia voluptate veniam id 35 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 36 | quisquam? Deleniti, eius. 37 |

38 |

39 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 40 | provident veritatis quos dolorum repellendus officia voluptate veniam id 41 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 42 | quisquam? Deleniti, eius. 43 |

44 |

45 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae suscipit, 46 | provident veritatis quos dolorum repellendus officia voluptate veniam id 47 | pariatur, maiores dolore libero nemo repudiandae facere reiciendis 48 | quisquam? Deleniti, eius. 49 |

50 |
51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /projects/background-image-scroll-effect/index.js: -------------------------------------------------------------------------------- 1 | const bgImageEl = document.getElementById("bg-image"); 2 | 3 | window.addEventListener("scroll", () => { 4 | updateImage(); 5 | }); 6 | 7 | function updateImage() { 8 | bgImageEl.style.opacity = 1 - window.pageYOffset / 900; 9 | bgImageEl.style.backgroundSize = 160 - window.pageYOffset / 12 + "%"; 10 | } 11 | -------------------------------------------------------------------------------- /projects/background-image-scroll-effect/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: sans-serif; 4 | } 5 | 6 | .bg-image { 7 | width: 100%; 8 | height: 100vh; 9 | background: url("https://images.unsplash.com/photo-1540206395-68808572332f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=626&q=80"); 10 | background-position: center; 11 | background-attachment: fixed; 12 | background-size: 160%; 13 | } 14 | 15 | .container { 16 | padding: 100px; 17 | } 18 | 19 | h1 { 20 | font-size: 50px; 21 | } 22 | p { 23 | color: grey; 24 | } 25 | 26 | @media (max-width: 500px) { 27 | .container { 28 | padding: 10px; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /projects/background-video/background-video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/background-video/background-video.mp4 -------------------------------------------------------------------------------- /projects/background-video/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sahand Ghavidel 8 | 9 | 10 | 11 | 12 | 13 |
14 | preloader 15 |
16 |
17 | 18 |

Sahand Ghavidel

19 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/background-video/index.js: -------------------------------------------------------------------------------- 1 | const btn = document.querySelector(".btn"); 2 | const video = document.querySelector(".background-video"); 3 | const fa = document.querySelector(".fa"); 4 | const preloader = document.querySelector(".preloader"); 5 | 6 | btn.addEventListener("click", () => { 7 | if (btn.classList.contains("pause")) { 8 | btn.classList.remove("pause"); 9 | video.play(); 10 | fa.classList.add("fa-pause"); 11 | fa.classList.remove("fa-play"); 12 | } else { 13 | btn.classList.add("pause"); 14 | video.pause(); 15 | fa.classList.remove("fa-pause"); 16 | fa.classList.add("fa-play"); 17 | } 18 | }); 19 | 20 | window.addEventListener("load", () => { 21 | preloader.style.zIndex = "-999"; 22 | }); 23 | -------------------------------------------------------------------------------- /projects/background-video/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/background-video/preloader.gif -------------------------------------------------------------------------------- /projects/background-video/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | 7 | h1 { 8 | font-size: 2.5rem; 9 | color: white; 10 | letter-spacing: 0.277em; 11 | font-weight: 300; 12 | } 13 | 14 | .background-video { 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | z-index: -1; 19 | width: 100%; 20 | height: 100%; 21 | object-fit: cover; 22 | filter: brightness(30%); 23 | } 24 | 25 | header { 26 | min-height: 100vh; 27 | display: grid; 28 | place-items: center; 29 | } 30 | 31 | .preloader { 32 | position: fixed; 33 | top: 0; 34 | left: 0; 35 | right: 0; 36 | bottom: 0; 37 | background: white; 38 | display: grid; 39 | justify-content: center; 40 | align-items: center; 41 | z-index: 999; 42 | transition: 0.1s linear; 43 | } 44 | -------------------------------------------------------------------------------- /projects/basic-calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Basic Calculator 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /projects/basic-calculator/index.js: -------------------------------------------------------------------------------- 1 | const buttonsEl = document.querySelectorAll("button"); 2 | 3 | const inputFieldEl = document.getElementById("result"); 4 | 5 | for (let i = 0; i < buttonsEl.length; i++) { 6 | buttonsEl[i].addEventListener("click", () => { 7 | const buttonValue = buttonsEl[i].textContent; 8 | if (buttonValue === "C") { 9 | clearResult(); 10 | } else if (buttonValue === "=") { 11 | calculateResult(); 12 | } else { 13 | appendValue(buttonValue); 14 | } 15 | }); 16 | } 17 | 18 | function clearResult() { 19 | inputFieldEl.value = ""; 20 | } 21 | 22 | function calculateResult() { 23 | inputFieldEl.value = eval(inputFieldEl.value); 24 | } 25 | 26 | function appendValue(buttonValue) { 27 | inputFieldEl.value += buttonValue; 28 | // inputFieldEl.value = inputFieldEl.value + buttonValue; 29 | } 30 | -------------------------------------------------------------------------------- /projects/basic-calculator/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | } 5 | 6 | .calculator { 7 | background-color: #f2f2f2; 8 | padding: 20px; 9 | max-width: 400px; 10 | margin: 0 auto; 11 | border: solid 1px #ccc; 12 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); 13 | border-radius: 5px; 14 | margin-top: 40px; 15 | } 16 | 17 | #result{ 18 | width: 100%; 19 | padding: 10px; 20 | font-size: 24px; 21 | border: none; 22 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3) inset; 23 | border-radius: 5px; 24 | } 25 | 26 | .buttons{ 27 | display: grid; 28 | grid-template-columns: repeat(4, 1fr); 29 | grid-gap: 10px; 30 | margin-top: 20px; 31 | } 32 | 33 | button{ 34 | padding: 10px; 35 | font-size: 24px; 36 | border: none; 37 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); 38 | border-radius: 5px; 39 | cursor: pointer; 40 | transition: background-color 0.3s ease; 41 | 42 | } 43 | 44 | button:hover{ 45 | background-color: #ddd; 46 | } 47 | 48 | .clear{ 49 | background-color: #ff4136; 50 | color: #fff; 51 | } 52 | 53 | .number, .decimal{ 54 | background-color: #fff; 55 | color: #333; 56 | 57 | } 58 | 59 | .operator{ 60 | background-color: #0074d9; 61 | color: #fff; 62 | } 63 | 64 | .equals{ 65 | background-color: #01ff70; 66 | grid-row: span 3; 67 | color: #fff; 68 | } -------------------------------------------------------------------------------- /projects/blurred-background-popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Blurred Background Popup 8 | 15 | 16 | 17 | 18 |
19 |

Welcome to our website

20 | 21 |
22 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /projects/blurred-background-popup/index.js: -------------------------------------------------------------------------------- 1 | const containerEl = document.querySelector(".container"); 2 | 3 | const btnEl = document.querySelector(".btn"); 4 | 5 | const popupContainerEl = document.querySelector(".popup-container"); 6 | 7 | const closeIconEl = document.querySelector(".close-icon"); 8 | 9 | btnEl.addEventListener("click", () => { 10 | containerEl.classList.add("active"); 11 | popupContainerEl.classList.remove("active"); 12 | }); 13 | 14 | closeIconEl.addEventListener("click", () => { 15 | containerEl.classList.remove("active"); 16 | popupContainerEl.classList.add("active"); 17 | }); 18 | -------------------------------------------------------------------------------- /projects/blurred-background-popup/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .container { 6 | display: flex; 7 | flex-direction: column; 8 | align-items: center; 9 | height: 100vh; 10 | justify-content: center; 11 | background: url("https://images.unsplash.com/photo-1560762484-813fc97650a0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1074&q=80"); 12 | background-size: cover; 13 | text-align: center; 14 | transition: filter 0.7s; 15 | } 16 | 17 | h1 { 18 | font-size: 60px; 19 | color: white; 20 | font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif; 21 | letter-spacing: 4px; 22 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); 23 | } 24 | 25 | .btn { 26 | padding: 10px 20px; 27 | width: 200px; 28 | cursor: pointer; 29 | background-color: orangered; 30 | border: none; 31 | border-radius: 5px; 32 | font-size: 20px; 33 | } 34 | 35 | .btn:hover { 36 | filter: brightness(0.8); 37 | } 38 | 39 | .active.container { 40 | filter: blur(5px) brightness(0.7); 41 | } 42 | 43 | .popup-container { 44 | position: fixed; 45 | left: 50%; 46 | transform: translateX(-50%); 47 | background-color: white; 48 | width: 400px; 49 | height: 200px; 50 | top: 30%; 51 | display: flex; 52 | flex-direction: column; 53 | padding: 20px; 54 | background: url("https://images.unsplash.com/uploads/141103282695035fa1380/95cdfeef?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1730&q=80"); 55 | background-size: cover; 56 | border-radius: 10px; 57 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 58 | opacity: 1; 59 | transition: all 0.7s; 60 | } 61 | 62 | h4 { 63 | font-size: 30px; 64 | margin: 10px 0; 65 | font-family: sans-serif; 66 | color: blueviolet; 67 | } 68 | 69 | label { 70 | color: blueviolet; 71 | font-family: sans-serif; 72 | } 73 | 74 | .popup-btn { 75 | background-color: orangered; 76 | padding: 10px; 77 | font-size: 20px; 78 | cursor: pointer; 79 | border: 2px solid; 80 | } 81 | 82 | .input { 83 | border: 2px solid; 84 | padding: 10px; 85 | margin: 10px 0; 86 | font-size: 20px; 87 | text-align: center; 88 | } 89 | 90 | .input::placeholder { 91 | color: lightgray; 92 | } 93 | 94 | .close-icon { 95 | position: absolute; 96 | right: 20px; 97 | cursor: pointer; 98 | } 99 | 100 | .close-icon:hover { 101 | color: orangered; 102 | } 103 | 104 | .active.popup-container { 105 | visibility: hidden; 106 | opacity: 0; 107 | top: 10%; 108 | } 109 | -------------------------------------------------------------------------------- /projects/bmi-calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BMI Calculator 8 | 9 | 10 | 11 |
12 |

Body Mass Index (BMI) Calculator

13 | Your Height (cm): 14 | 15 | Your Weight (kg): 16 | 17 | 18 | 19 |

Weight Condition:

20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /projects/bmi-calculator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const bmiInputEl = document.getElementById("bmi-result"); 3 | const weightConditionEl = document.getElementById("weight-condition"); 4 | 5 | function calculateBMI() { 6 | const heightValue = document.getElementById("height").value / 100; 7 | const weightValue = document.getElementById("weight").value; 8 | 9 | const bmiValue = weightValue / (heightValue * heightValue); 10 | 11 | bmiInputEl.value = bmiValue; 12 | 13 | if (bmiValue < 18.5) { 14 | weightConditionEl.innerText = "Under weight"; 15 | } else if (bmiValue >= 18.5 && bmiValue <= 24.9) { 16 | weightConditionEl.innerText = "Normal weight"; 17 | } else if (bmiValue >= 25 && bmiValue <= 29.9) { 18 | weightConditionEl.innerText = "Overweight"; 19 | } else if (bmiValue >= 30) { 20 | weightConditionEl.innerText = "Obesity"; 21 | } 22 | } 23 | 24 | btnEl.addEventListener("click", calculateBMI); 25 | -------------------------------------------------------------------------------- /projects/bmi-calculator/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | background: linear-gradient(to left bottom, lightgreen, lightblue); 4 | display: flex; 5 | min-height: 100vh; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: 'Courier New', Courier, monospace; 9 | } 10 | 11 | .container{ 12 | background: rgba(255,255,255, .3); 13 | padding: 20px; 14 | display: flex; 15 | flex-direction: column; 16 | border-radius: 5px; 17 | box-shadow: 0 10px 10px rgba(0,0,0,.3); 18 | margin: 5px; 19 | } 20 | 21 | .heading{ 22 | font-size: 30px; 23 | } 24 | 25 | .input{ 26 | padding: 10px 20px; 27 | font-size: 18px; 28 | background: rgba(255,255,255, .4); 29 | border-color: rgba(255,255,255, .5); 30 | margin: 10px; 31 | } 32 | 33 | .btn{ 34 | background-color: lightgreen; 35 | border: none; 36 | padding: 10px 20px; 37 | border-radius: 5px; 38 | margin: 10px; 39 | font-size: 20px; 40 | box-shadow: 0 0 4px rgba(0,0,0,.3); 41 | cursor: pointer; 42 | } 43 | 44 | .btn:hover{ 45 | box-shadow: 0 0 8px rgba(0,0,0,.3); 46 | transition: all 300ms ease; 47 | } 48 | 49 | .info-text{ 50 | font-size: 20px; 51 | font-weight: 500; 52 | } -------------------------------------------------------------------------------- /projects/button-ripple-effect/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Button Ripple Effect 8 | 9 | 10 | 11 | Button 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/button-ripple-effect/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.querySelector(".btn"); 2 | 3 | btnEl.addEventListener("mouseover", (event) => { 4 | const x = event.pageX - btnEl.offsetLeft; 5 | const y = event.pageY - btnEl.offsetTop; 6 | 7 | btnEl.style.setProperty("--xPos", x + "px"); 8 | btnEl.style.setProperty("--yPos", y + "px"); 9 | }); 10 | -------------------------------------------------------------------------------- /projects/button-ripple-effect/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: aliceblue; 8 | font-family: sans-serif; 9 | } 10 | 11 | .btn { 12 | background-color: pink; 13 | padding: 20px 40px; 14 | border-radius: 5px; 15 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 16 | text-decoration: none; 17 | color: black; 18 | position: relative; 19 | overflow: hidden; 20 | } 21 | 22 | .btn span { 23 | position: relative; 24 | z-index: 1; 25 | } 26 | 27 | .btn::before { 28 | content: ""; 29 | position: absolute; 30 | background-color: orangered; 31 | width: 0; 32 | height: 0; 33 | left: var(--xPos); 34 | top: var(--yPos); 35 | transform: translate(-50%, -50%); 36 | border-radius: 50%; 37 | transition: width 0.5s, height 0.5s; 38 | } 39 | 40 | .btn:hover::before { 41 | width: 300px; 42 | height: 300px; 43 | } 44 | -------------------------------------------------------------------------------- /projects/clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Clock 9 | 10 | 11 |
12 |
13 |
12
14 |
3
15 |
6
16 |
9
17 |
18 |
19 |
20 |
21 |
22 |
23 | 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /projects/clock/index.js: -------------------------------------------------------------------------------- 1 | const hour = document.querySelector(".hour"); 2 | const minute = document.querySelector(".minute"); 3 | const second = document.querySelector(".second"); 4 | 5 | function setDate() { 6 | const now = new Date(); 7 | 8 | const getSecond = now.getSeconds(); 9 | const getMinute = now.getMinutes(); 10 | const getHour = now.getHours(); 11 | 12 | const secondDegree = (getSecond / 60) * 360; 13 | const minuteDegree = (getMinute / 60) * 360; 14 | const hourDegree = (getHour / 12) * 360; 15 | 16 | second.style.transform = `rotate(${secondDegree}deg)`; 17 | minute.style.transform = `rotate(${minuteDegree}deg)`; 18 | hour.style.transform = `rotate(${hourDegree}deg)`; 19 | } 20 | 21 | setInterval(setDate, 1000); 22 | -------------------------------------------------------------------------------- /projects/clock/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | font-family: 'Courier New', Courier, monospace; 6 | height: 100vh; 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | background-color: salmon; 11 | } 12 | 13 | img { 14 | position: absolute; 15 | top: 60px; 16 | left: 50%; 17 | transform: translateX(-50%); 18 | width: 70px; 19 | z-index: 2; 20 | } 21 | 22 | .clock { 23 | width: 350px; 24 | height: 350px; 25 | background-color: lightgray; 26 | border-radius: 100%; 27 | border: 5px solid darkgrey; 28 | box-shadow: 1px 1px 4px rgba(0,0,0,.7); 29 | position: relative; 30 | } 31 | 32 | 33 | 34 | .numbers div { 35 | position: absolute; 36 | font-size: 27px; 37 | font-weight: bold; 38 | color: lightgoldenrodyellow; 39 | text-shadow: 1px 1px 2px rgba(0,0,0,.7); 40 | } 41 | 42 | .twelve { 43 | top: 6px; 44 | left: 50%; 45 | transform: translateX(-50%); 46 | } 47 | 48 | .three { 49 | right: 6px; 50 | top: 50%; 51 | transform: translateY(-50%); 52 | } 53 | 54 | .six { 55 | bottom: 6px; 56 | left: 50%; 57 | transform: translateX(-50%); 58 | } 59 | 60 | .nine { 61 | left: 6px; 62 | top: 50%; 63 | transform: translateY(-50%); 64 | } 65 | 66 | .arrows { 67 | width: 100%; 68 | height: 100%; 69 | display: flex; 70 | justify-content: center; 71 | align-items: center; 72 | } 73 | 74 | .arrows::before { 75 | content: ""; 76 | width: 25px; 77 | height: 25px; 78 | background-color: darkgreen; 79 | border-radius: 50%; 80 | box-shadow: 1px 1px 2px rgba(0,0,0,.7); 81 | z-index: 4; 82 | } 83 | 84 | .arrows div { 85 | width: 7px; 86 | height: 120px; 87 | background-color: white; 88 | position: absolute; 89 | bottom: 50%; 90 | box-shadow: 1px 1px 2px rgba(0,0,0,.7); 91 | border-radius: 50% 50% 0 0; 92 | transform-origin: bottom center; 93 | z-index: 3; 94 | } 95 | 96 | .arrows .hour { 97 | height: 80px; 98 | transform: rotate(30deg); 99 | } 100 | 101 | .arrows .second { 102 | background-color: goldenrod; 103 | transform: rotate(250deg); 104 | 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /projects/counter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Counter Project 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

Counter

15 | 0 16 |
17 | 18 | 19 | 21 |
22 |
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/counter/index.js: -------------------------------------------------------------------------------- 1 | let num = 0; 2 | 3 | const value = document.querySelector(".value"); 4 | const btns = document.querySelectorAll(".btn"); 5 | 6 | btns.forEach((btn) => { 7 | btn.addEventListener("click", (e) => { 8 | const styles = e.currentTarget.classList; 9 | if (styles.contains("decrease")) { 10 | num--; 11 | } else if (styles.contains("increase")) { 12 | num++; 13 | } else { 14 | num = 0; 15 | } 16 | value.textContent = num; 17 | if (num > 0) { 18 | value.style.color = "green"; 19 | } else if (num < 0) { 20 | value.style.color = "red"; 21 | } else { 22 | value.style.color = "black"; 23 | } 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/counter/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | text-align: center; 6 | } 7 | 8 | h1 { 9 | font-size: 4rem; 10 | } 11 | 12 | .value { 13 | font-size: 6rem; 14 | } 15 | -------------------------------------------------------------------------------- /projects/currency-converter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Currency Converter 8 | 9 | 10 | 11 |
12 |

Currency Converter

13 |
14 | 23 | 24 |
25 |
26 | 35 | 36 |
37 |

1 USD = 138.5802 JPY

38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /projects/currency-converter/index.js: -------------------------------------------------------------------------------- 1 | const currencyFirstEl = document.getElementById("currency-first"); 2 | 3 | const worthFirstEl = document.getElementById("worth-first"); 4 | 5 | const currencySecondEl = document.getElementById("currency-second"); 6 | 7 | const worthSecondEl = document.getElementById("worth-second"); 8 | 9 | const exchangeRateEl = document.getElementById("exchange-rate"); 10 | 11 | updateRate() 12 | 13 | function updateRate() { 14 | fetch( 15 | `https://v6.exchangerate-api.com/v6/5f9d1c87f7250159c9c9b17d/latest/${currencyFirstEl.value}` 16 | ) 17 | .then((res) => res.json()) 18 | .then((data) => { 19 | const rate = data.conversion_rates[currencySecondEl.value]; 20 | console.log(rate); 21 | exchangeRateEl.innerText = `1 ${currencyFirstEl.value} = ${ 22 | rate + " " + currencySecondEl.value 23 | }`; 24 | 25 | worthSecondEl.value = (worthFirstEl.value * rate).toFixed(2) 26 | }); 27 | } 28 | 29 | currencyFirstEl.addEventListener("change", updateRate); 30 | 31 | currencySecondEl.addEventListener("change", updateRate); 32 | 33 | worthFirstEl.addEventListener("input", updateRate); 34 | -------------------------------------------------------------------------------- /projects/currency-converter/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: yellow; 3 | display: flex; 4 | height: 100vh; 5 | justify-content: center; 6 | align-items: center; 7 | font-family: 'Courier New', Courier, monospace; 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | .container{ 13 | background-color: darkcyan; 14 | color: aliceblue; 15 | padding: 10px; 16 | border-radius: 5px; 17 | text-align: center; 18 | } 19 | 20 | 21 | .currency-container{ 22 | padding: 20px; 23 | display: flex; 24 | justify-content: space-between; 25 | } 26 | 27 | .currency-container select{ 28 | padding: 10px; 29 | } 30 | 31 | .currency-container input{ 32 | border: 0; 33 | background: transparent; 34 | font-size: 25px; 35 | text-align: right; 36 | color: aliceblue; 37 | } 38 | 39 | .exchange-rate{ 40 | font-size: 16px; 41 | font-weight: 600; 42 | } 43 | 44 | select:focus, 45 | input:focus{ 46 | outline: 0; 47 | } -------------------------------------------------------------------------------- /projects/dad-jokes-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dad Jokes Generator 8 | 9 | 10 | 11 |
12 |

Dad Joke Generator

13 |

Dad Joke

14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /projects/dad-jokes-generator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const jokeEl = document.getElementById("joke"); 3 | 4 | const apiKey = "4kqGcJx8uDXo3XIskcbzokAz7rN8nWJs3PL9Mcll"; 5 | 6 | const options = { 7 | method: "GET", 8 | headers: { 9 | "X-Api-Key": apiKey, 10 | }, 11 | }; 12 | 13 | const apiURL = "https://api.api-ninjas.com/v1/dadjokes?limit=1"; 14 | 15 | async function getJoke() { 16 | try { 17 | jokeEl.innerText = "Updating..."; 18 | btnEl.disabled = true; 19 | btnEl.innerText = "Loading..."; 20 | const response = await fetch(apiURL, options); 21 | const data = await response.json(); 22 | 23 | btnEl.disabled = false; 24 | btnEl.innerText = "Tell me a joke"; 25 | 26 | jokeEl.innerText = data[0].joke; 27 | } catch (error) { 28 | jokeEl.innerText = "An error happened, try again later"; 29 | btnEl.disabled = false; 30 | btnEl.innerText = "Tell me a joke"; 31 | console.log(error); 32 | } 33 | } 34 | 35 | btnEl.addEventListener("click", getJoke); 36 | 37 | -------------------------------------------------------------------------------- /projects/dad-jokes-generator/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | background: linear-gradient(to left bottom, lightblue, lightpink, lightblue); 4 | min-height: 100vh; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: monospace; 9 | } 10 | 11 | .container{ 12 | background-color: rgba(255,255,255,.3); 13 | padding: 20px; 14 | box-shadow: 0 6px 10px rgba(0,0,0,.3); 15 | border-radius: 15px; 16 | width: 85%; 17 | text-align: center; 18 | color: darkgreen; 19 | } 20 | 21 | .heading{ 22 | font-size: 35px; 23 | font-weight: 200; 24 | font-family: Impact, Haettenschweiler, 'Arial Narrow Bold', sans-serif; 25 | text-shadow: 5px 5px 2px rgba(0,0,0,.3); 26 | letter-spacing: 2px; 27 | } 28 | 29 | .joke{ 30 | font-size: 25px; 31 | font-weight: 500; 32 | margin: 40px 33 | } 34 | 35 | .btn{ 36 | font-size: 18px; 37 | font-weight: 700; 38 | border-radius: 5px; 39 | cursor: pointer; 40 | padding: 10px; 41 | background-color: rgba(255,255,255,.3); 42 | border-color: rgba(255,255,255,.6); 43 | text-transform: uppercase; 44 | width: 300px; 45 | color: darkgreen; 46 | } 47 | 48 | .btn:hover{ 49 | background-color: rgba(255,255,255,.5); 50 | box-shadow: 0 4px 4px rgba(0,0,0,.3); 51 | transition: all 300ms ease; 52 | } -------------------------------------------------------------------------------- /projects/dark-mode-toggle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dark Mode Toggle 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /projects/dark-mode-toggle/index.js: -------------------------------------------------------------------------------- 1 | const inputEl = document.querySelector(".input"); 2 | 3 | const bodyEl = document.querySelector("body"); 4 | 5 | inputEl.checked = JSON.parse(localStorage.getItem("mode")); 6 | 7 | updateBody(); 8 | 9 | function updateBody() { 10 | if (inputEl.checked) { 11 | bodyEl.style.background = "black"; 12 | } else { 13 | bodyEl.style.background = "white"; 14 | } 15 | } 16 | 17 | inputEl.addEventListener("input", () => { 18 | updateBody(); 19 | updateLocalStorage(); 20 | }); 21 | 22 | function updateLocalStorage() { 23 | localStorage.setItem("mode", JSON.stringify(inputEl.checked)); 24 | } 25 | -------------------------------------------------------------------------------- /projects/dark-mode-toggle/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | transition: .4s; 8 | } 9 | 10 | .input { 11 | visibility: hidden; 12 | } 13 | 14 | .label { 15 | position: absolute; 16 | width: 80px; 17 | height: 40px; 18 | background-color: lightgray; 19 | border-radius: 20px; 20 | cursor: pointer; 21 | } 22 | 23 | .circle { 24 | width: 34px; 25 | background-color: white; 26 | height: 34px; 27 | border-radius: 50%; 28 | top: 3px; 29 | position: absolute; 30 | left: 3px; 31 | animation: toggleOff 0.4s linear forwards; 32 | } 33 | 34 | .input:checked + .label { 35 | background-color: white; 36 | } 37 | 38 | .input:checked + .label .circle { 39 | animation: toggleOn 0.4s linear forwards; 40 | background-color: black; 41 | } 42 | 43 | @keyframes toggleOn { 44 | 0% { 45 | transform: translateX(0); 46 | } 47 | 100% { 48 | transform: translateX(40px); 49 | } 50 | } 51 | 52 | @keyframes toggleOff { 53 | 0% { 54 | transform: translateX(40px); 55 | } 56 | 100% { 57 | transform: translateX(0); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /projects/dice-roll-simulator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Dice Roll Simulator 8 | 9 | 10 | 11 |

Dice Roll Simulator

12 |
13 | 14 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /projects/dice-roll-simulator/index.js: -------------------------------------------------------------------------------- 1 | const buttonEl = document.getElementById("roll-button"); 2 | 3 | const diceEl = document.getElementById("dice"); 4 | 5 | const rollHistoryEl = document.getElementById("roll-history"); 6 | 7 | let historyList = []; 8 | 9 | function rollDice() { 10 | const rollResult = Math.floor(Math.random() * 6) + 1; 11 | const diceFace = getDiceFace(rollResult); 12 | diceEl.innerHTML = diceFace; 13 | historyList.push(rollResult); 14 | updateRollHistory(); 15 | } 16 | 17 | function updateRollHistory() { 18 | rollHistoryEl.innerHTML = ""; 19 | for (let i = 0; i < historyList.length; i++) { 20 | const listItem = document.createElement("li"); 21 | listItem.innerHTML = `Roll ${i + 1}: ${getDiceFace( 22 | historyList[i] 23 | )}`; 24 | rollHistoryEl.appendChild(listItem); 25 | } 26 | } 27 | 28 | function getDiceFace(rollResult) { 29 | switch (rollResult) { 30 | case 1: 31 | return "⚀"; 32 | case 2: 33 | return "⚁"; 34 | case 3: 35 | return "⚂"; 36 | case 4: 37 | return "⚃"; 38 | case 5: 39 | return "⚄"; 40 | case 6: 41 | return "⚅"; 42 | default: 43 | return ""; 44 | } 45 | } 46 | 47 | buttonEl.addEventListener("click", () => { 48 | diceEl.classList.add("roll-animation"); 49 | setTimeout(() => { 50 | diceEl.classList.remove("roll-animation"); 51 | rollDice(); 52 | }, 1000); 53 | }); 54 | -------------------------------------------------------------------------------- /projects/dice-roll-simulator/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Open Sans", sans-serif; 3 | text-align: center; 4 | margin: 0; 5 | } 6 | 7 | h1 { 8 | font-size: 3rem; 9 | margin-top: 2rem; 10 | } 11 | 12 | .dice { 13 | font-size: 7rem; 14 | margin: 5px; 15 | animation-duration: 1s; 16 | animation-fill-mode: forwards; 17 | } 18 | 19 | .roll-animation { 20 | animation-name: roll; 21 | } 22 | 23 | @keyframes roll { 24 | 0% { 25 | transform: rotateY(0deg) rotateX(0deg); 26 | } 27 | 28 | 100% { 29 | transform: rotateY(720deg) rotateX(720deg); 30 | } 31 | } 32 | 33 | button { 34 | background-color: #47a5c4; 35 | color: white; 36 | font-size: 1.5rem; 37 | padding: 1rem 2rem; 38 | border: none; 39 | border-radius: 1rem; 40 | cursor: pointer; 41 | transition: background-color 0.3s ease; 42 | } 43 | 44 | button:hover { 45 | background-color: #2e8baf; 46 | } 47 | 48 | ul { 49 | list-style: none; 50 | padding: 0; 51 | max-width: 600px; 52 | margin: 2rem auto; 53 | } 54 | 55 | li { 56 | font-size: 1.5rem; 57 | padding: 0.5rem; 58 | margin: 0.5rem; 59 | background-color: #f2f2f2; 60 | border-radius: 0.5rem; 61 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.3); 62 | display: flex; 63 | justify-content: space-between; 64 | align-items: center; 65 | } 66 | 67 | li span { 68 | font-size: 3rem; 69 | margin-right: 1rem; 70 | } 71 | -------------------------------------------------------------------------------- /projects/digital-clock/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Digital Clock 8 | 9 | 10 | 11 |

Digital Clock

12 |
13 |
14 | 00 15 | Hours 16 |
17 |
18 | 00 19 | Minutes 20 |
21 |
22 | 00 23 | Seconds 24 |
25 |
26 | AM 27 |
28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /projects/digital-clock/index.js: -------------------------------------------------------------------------------- 1 | const hourEl = document.getElementById("hour"); 2 | const minuteEl = document.getElementById("minutes"); 3 | const secondEl = document.getElementById("seconds"); 4 | const ampmEl = document.getElementById("ampm"); 5 | 6 | function updateClock() { 7 | let h = new Date().getHours(); 8 | let m = new Date().getMinutes(); 9 | let s = new Date().getSeconds(); 10 | let ampm = "AM"; 11 | 12 | if (h > 12) { 13 | h = h - 12; 14 | ampm = "PM"; 15 | } 16 | 17 | h = h < 10 ? "0" + h : h; 18 | m = m < 10 ? "0" + m : m; 19 | s = s < 10 ? "0" + s : s; 20 | 21 | hourEl.innerText = h; 22 | minuteEl.innerText = m; 23 | secondEl.innerText = s; 24 | ampmEl.innerText = ampm; 25 | setTimeout(() => { 26 | updateClock(); 27 | }, 1000); 28 | } 29 | 30 | updateClock(); 31 | -------------------------------------------------------------------------------- /projects/digital-clock/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: sans-serif; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | height: 100vh; 8 | justify-content: center; 9 | background: url("https://images.unsplash.com/photo-1499002238440-d264edd596ec?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"); 10 | background-size: cover; 11 | overflow: hidden; 12 | } 13 | 14 | h2 { 15 | text-transform: uppercase; 16 | letter-spacing: 4px; 17 | font-size: 14px; 18 | text-align: center; 19 | color: white; 20 | } 21 | 22 | .clock { 23 | display: flex; 24 | } 25 | 26 | .clock div { 27 | margin: 5px; 28 | position: relative; 29 | } 30 | 31 | .clock span { 32 | width: 100px; 33 | height: 80px; 34 | background: slateblue; 35 | opacity: 0.8; 36 | color: white; 37 | display: flex; 38 | justify-content: center; 39 | align-items: center; 40 | font-size: 50px; 41 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); 42 | } 43 | 44 | .clock .text { 45 | height: 30px; 46 | font-size: 10px; 47 | text-transform: uppercase; 48 | letter-spacing: 2px; 49 | background: darkblue; 50 | opacity: 0.8; 51 | } 52 | 53 | .clock #ampm { 54 | bottom: 0; 55 | position: absolute; 56 | width: 60px; 57 | height: 30px; 58 | font-size: 20px; 59 | background: green; 60 | } 61 | -------------------------------------------------------------------------------- /projects/double-landing-page/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Double Landing Page 8 | 9 | 10 | 11 |
12 |
13 |

Apple

14 | 15 |
16 |
17 |

Samsung

18 | 19 |
20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/double-landing-page/index.js: -------------------------------------------------------------------------------- 1 | const containerEl = document.querySelector(".container"); 2 | 3 | const leftEl = document.querySelector(".left"); 4 | const rightEl = document.querySelector(".right"); 5 | 6 | leftEl.addEventListener("mouseenter", () => { 7 | containerEl.classList.add("active-left"); 8 | }); 9 | 10 | leftEl.addEventListener("mouseleave", () => { 11 | containerEl.classList.remove("active-left"); 12 | }); 13 | 14 | rightEl.addEventListener("mouseenter", () => { 15 | containerEl.classList.add("active-right"); 16 | }); 17 | 18 | rightEl.addEventListener("mouseleave", () => { 19 | containerEl.classList.remove("active-right"); 20 | }); 21 | -------------------------------------------------------------------------------- /projects/double-landing-page/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | text-align: center; 8 | font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif; 9 | } 10 | 11 | h1 { 12 | font-size: 100px; 13 | color: aliceblue; 14 | background-color: rgba(0, 0, 0, 0.3); 15 | letter-spacing: 4px; 16 | } 17 | 18 | .btn { 19 | background-color: black; 20 | color: white; 21 | padding: 20px 40px; 22 | font-size: 25px; 23 | border: 4px solid; 24 | cursor: pointer; 25 | transition: 1s background-color; 26 | white-space: nowrap; 27 | } 28 | 29 | .btn:hover { 30 | background-color: white; 31 | color: black; 32 | } 33 | 34 | .split { 35 | width: 50%; 36 | height: 100%; 37 | top: 0; 38 | overflow: hidden; 39 | } 40 | 41 | .split.left { 42 | position: absolute; 43 | left: 0; 44 | background-color: pink; 45 | background-image: url("https://store.storeimages.cdn-apple.com/4982/as-images.apple.com/is/iphone-13-pro-family-hero?wid=940&hei=1112&fmt=png-alpha&.v=1631220221000"); 46 | background-size: cover; 47 | } 48 | 49 | .split.right { 50 | position: absolute; 51 | right: 0; 52 | background-color: lightblue; 53 | background-image: url("https://pisces.bbystatic.com/image2/BestBuy_US/images/products/6465/6465022_sd.jpg;maxHeight=640;maxWidth=550"); 54 | background-size: cover; 55 | } 56 | 57 | .active-left .left { 58 | width: 75%; 59 | } 60 | 61 | .active-left .right { 62 | width: 25%; 63 | } 64 | 65 | .active-right .left { 66 | width: 25%; 67 | } 68 | 69 | .active-right .right { 70 | width: 75%; 71 | } 72 | 73 | .left, 74 | .right { 75 | transition: width 2s ease-in-out; 76 | } 77 | -------------------------------------------------------------------------------- /projects/drum-kits/images/crash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/images/crash.png -------------------------------------------------------------------------------- /projects/drum-kits/images/kick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/images/kick.png -------------------------------------------------------------------------------- /projects/drum-kits/images/snare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/images/snare.png -------------------------------------------------------------------------------- /projects/drum-kits/images/tom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/images/tom.png -------------------------------------------------------------------------------- /projects/drum-kits/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Drum Kits 8 | 15 | 16 | 17 | 18 |

Drum Kits

19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /projects/drum-kits/index.js: -------------------------------------------------------------------------------- 1 | const kits = ["crash", "kick", "snare", "tom"]; 2 | 3 | const containerEl = document.querySelector(".container"); 4 | 5 | kits.forEach((kit) => { 6 | const btnEl = document.createElement("button"); 7 | btnEl.classList.add("btn"); 8 | btnEl.innerText = kit; 9 | btnEl.style.backgroundImage = "url(images/" + kit + ".png)"; 10 | containerEl.appendChild(btnEl); 11 | const audioEl = document.createElement("audio"); 12 | audioEl.src = "sounds/" + kit + ".mp3"; 13 | containerEl.appendChild(audioEl); 14 | btnEl.addEventListener("click", () => { 15 | audioEl.play(); 16 | }); 17 | window.addEventListener("keydown", (event) => { 18 | if (event.key === kit.slice(0, 1)) { 19 | audioEl.play(); 20 | btnEl.style.transform = "scale(.9)"; 21 | setTimeout(() => { 22 | btnEl.style.transform = "scale(1)"; 23 | }, 100); 24 | } 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /projects/drum-kits/sounds/crash.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/sounds/crash.mp3 -------------------------------------------------------------------------------- /projects/drum-kits/sounds/kick.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/sounds/kick.mp3 -------------------------------------------------------------------------------- /projects/drum-kits/sounds/snare.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/sounds/snare.mp3 -------------------------------------------------------------------------------- /projects/drum-kits/sounds/tom.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/drum-kits/sounds/tom.mp3 -------------------------------------------------------------------------------- /projects/drum-kits/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | height: 100vh; 7 | justify-content: center; 8 | background-color: pink; 9 | } 10 | 11 | h1 { 12 | font-size: 50px; 13 | font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif; 14 | letter-spacing: 4px; 15 | color: white; 16 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); 17 | white-space: nowrap; 18 | } 19 | 20 | .container { 21 | text-align: center; 22 | } 23 | 24 | .btn { 25 | padding: 30px 50px; 26 | background-color: white; 27 | border: none; 28 | margin: 10px; 29 | font-size: 30px; 30 | min-width: 200px; 31 | border-radius: 10px; 32 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 33 | background-image: url("images/tom.png"); 34 | background-size: cover; 35 | color: white; 36 | font-family: cursive; 37 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); 38 | cursor: pointer; 39 | text-transform: capitalize; 40 | } 41 | 42 | .btn:hover { 43 | color: pink; 44 | } 45 | 46 | .btn:active { 47 | background-size: 105%; 48 | } 49 | -------------------------------------------------------------------------------- /projects/emoji-rating/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Emoji Rating 8 | 15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /projects/emoji-rating/index.js: -------------------------------------------------------------------------------- 1 | const starsEl = document.querySelectorAll(".fa-star"); 2 | const emojisEl = document.querySelectorAll(".far"); 3 | const colorsArray = ["red", "orange", "lightblue", "lightgreen", "green"]; 4 | 5 | updateRating(0); 6 | 7 | starsEl.forEach((starEl, index) => { 8 | starEl.addEventListener("click", () => { 9 | updateRating(index); 10 | }); 11 | }); 12 | 13 | function updateRating(index) { 14 | starsEl.forEach((starEl, idx) => { 15 | if (idx < index + 1) { 16 | starEl.classList.add("active"); 17 | } else { 18 | starEl.classList.remove("active"); 19 | } 20 | }); 21 | 22 | emojisEl.forEach((emojiEl) => { 23 | emojiEl.style.transform = `translateX(-${index * 50}px)`; 24 | emojiEl.style.color = colorsArray[index]; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /projects/emoji-rating/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: yellow; 8 | } 9 | 10 | .feedback-container { 11 | background-color: white; 12 | width: 400px; 13 | height: 200px; 14 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 15 | border-radius: 10px; 16 | position: relative; 17 | } 18 | 19 | .emoji-container { 20 | position: absolute; 21 | left: 50%; 22 | transform: translateX(-50%); 23 | top: 20%; 24 | width: 50px; 25 | height: 50px; 26 | border-radius: 50%; 27 | display: flex; 28 | overflow: hidden; 29 | } 30 | 31 | .far { 32 | margin: 1px; 33 | transform: translateX(0); 34 | transition: transform 0.2s; 35 | } 36 | 37 | .rating-container { 38 | position: absolute; 39 | left: 50%; 40 | transform: translateX(-50%); 41 | bottom: 20%; 42 | } 43 | 44 | .fa-star { 45 | color: lightgray; 46 | cursor: pointer; 47 | } 48 | 49 | .fa-star.active { 50 | color: gold; 51 | } 52 | -------------------------------------------------------------------------------- /projects/english-dictionary/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | English Dictionary 8 | 9 | 10 | 11 |
12 |

English Dictionary

13 | 14 |

Type a word and press enter

15 |
16 |

Word Title: ___

17 |

Meaning: ___

18 | 19 |
20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/english-dictionary/index.js: -------------------------------------------------------------------------------- 1 | const inputEl = document.getElementById("input"); 2 | const infoTextEl = document.getElementById("info-text"); 3 | const meaningContainerEl = document.getElementById("meaning-container"); 4 | const titleEl = document.getElementById("title"); 5 | const meaningEl = document.getElementById("meaning"); 6 | const audioEl = document.getElementById("audio"); 7 | 8 | async function fetchAPI(word) { 9 | try { 10 | infoTextEl.style.display = "block"; 11 | meaningContainerEl.style.display = "none"; 12 | infoTextEl.innerText = `Searching the meaning of "${word}"`; 13 | const url = `https://api.dictionaryapi.dev/api/v2/entries/en/${word}`; 14 | const result = await fetch(url).then((res) => res.json()); 15 | 16 | if (result.title) { 17 | meaningContainerEl.style.display = "block"; 18 | infoTextEl.style.display = "none"; 19 | titleEl.innerText = word; 20 | meaningEl.innerText = "N/A"; 21 | audioEl.style.display = "none"; 22 | } else { 23 | infoTextEl.style.display = "none"; 24 | meaningContainerEl.style.display = "block"; 25 | audioEl.style.display = "inline-flex"; 26 | titleEl.innerText = result[0].word; 27 | meaningEl.innerText = result[0].meanings[0].definitions[0].definition; 28 | audioEl.src = result[0].phonetics[0].audio; 29 | } 30 | } catch (error) { 31 | console.log(error); 32 | infoTextEl.innerText = `an error happened, try again later`; 33 | } 34 | } 35 | 36 | inputEl.addEventListener("keyup", (e) => { 37 | if (e.target.value && e.key === "Enter") { 38 | fetchAPI(e.target.value); 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /projects/english-dictionary/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | display: flex; 4 | min-height: 100vh; 5 | justify-content: center; 6 | align-items: center; 7 | background-color: salmon; 8 | font-family: 'Courier New', Courier, monospace; 9 | } 10 | 11 | .container{ 12 | background-color: rgba(255,255,255, .3); 13 | padding: 28px; 14 | border-radius: 7px; 15 | box-shadow: 0 10px 10px rgba(0,0,0,.3); 16 | width: 90%; 17 | margin: 10px; 18 | max-width: 450px; 19 | text-align: center; 20 | font-size: 18px; 21 | font-weight: 500; 22 | } 23 | 24 | .heading{ 25 | font-size: 28px; 26 | } 27 | 28 | .input{ 29 | height: 53px; 30 | width: 300px; 31 | background-color: rgba(255,255,255, .6); 32 | border-color: rgba(255,255,255, .4); 33 | font-size: 16px; 34 | padding: 0 42px; 35 | border-radius: 5px; 36 | } 37 | 38 | .meaning-container{ 39 | display: none; 40 | } -------------------------------------------------------------------------------- /projects/feedback-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Feedback UI 8 | 9 | 10 | 11 |
12 |

Feedback UI

13 |
14 |
15 | 16 | Unhappy 17 |
18 |
19 | 20 | Neutral 21 |
22 |
23 | 24 | Satisfied 25 |
26 |
27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /projects/feedback-ui/index.js: -------------------------------------------------------------------------------- 1 | const ratingEls = document.querySelectorAll(".rating"); 2 | const btnEl = document.getElementById("btn"); 3 | 4 | const containerEl = document.getElementById("container"); 5 | 6 | let selectedRating = ""; 7 | 8 | ratingEls.forEach((ratingEl) => { 9 | ratingEl.addEventListener("click", (event) => { 10 | removeActive(); 11 | selectedRating = 12 | event.target.innerText || event.target.parentNode.innerText; 13 | event.target.classList.add("active"); 14 | event.target.parentNode.classList.add("active"); 15 | }); 16 | }); 17 | 18 | btnEl.addEventListener("click", () => { 19 | if (selectedRating !== "") { 20 | containerEl.innerHTML = ` 21 | Thank you! 22 |
23 |
24 | Feedback: ${selectedRating} 25 |

We'll use your feedback to improve our customer support.

26 | `; 27 | } 28 | }); 29 | 30 | function removeActive() { 31 | ratingEls.forEach((ratingEl) => { 32 | ratingEl.classList.remove("active"); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /projects/feedback-ui/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: lightcyan; 4 | color: darkgreen; 5 | display: flex; 6 | min-height: 100vh; 7 | justify-content: center; 8 | align-items: center; 9 | font-family: monospace; 10 | } 11 | 12 | .container { 13 | background: rgba(255, 255, 255, 0.3); 14 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); 15 | border-radius: 10px; 16 | padding: 20px; 17 | width: 85%; 18 | max-width: 400px; 19 | text-align: center; 20 | font-size: 20px; 21 | } 22 | 23 | .heading { 24 | margin: 5px; 25 | font-size: 30px; 26 | } 27 | 28 | .ratings-container { 29 | display: flex; 30 | padding: 20px 0; 31 | } 32 | 33 | .rating { 34 | cursor: pointer; 35 | padding: 10px; 36 | margin: 10px 5px; 37 | } 38 | 39 | .rating:hover, 40 | .rating.active 41 | { 42 | background: darkseagreen; 43 | border-radius: 10px; 44 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); 45 | color: aliceblue; 46 | transition: all 300ms ease; 47 | } 48 | 49 | .btn { 50 | background-color: darkcyan; 51 | color: aliceblue; 52 | border: 0; 53 | margin: 10px; 54 | border-radius: 4px; 55 | padding: 12px 30px; 56 | cursor: pointer; 57 | } 58 | 59 | .btn:hover { 60 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); 61 | transition: all 300ms ease; 62 | } 63 | 64 | .btn:active { 65 | transform: scale(0.96); 66 | } 67 | 68 | .rating img { 69 | width: 40px; 70 | } 71 | -------------------------------------------------------------------------------- /projects/heart-trail-animation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Heart Trail Animation 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /projects/heart-trail-animation/index.js: -------------------------------------------------------------------------------- 1 | const bodyEl = document.querySelector("body"); 2 | 3 | bodyEl.addEventListener("mousemove", (event) => { 4 | const xPos = event.offsetX; 5 | const yPos = event.offsetY; 6 | const spanEl = document.createElement("span"); 7 | spanEl.style.left = xPos + "px"; 8 | spanEl.style.top = yPos + "px"; 9 | const size = Math.random() * 100; 10 | spanEl.style.width = size + "px"; 11 | spanEl.style.height = size + "px"; 12 | bodyEl.appendChild(spanEl); 13 | setTimeout(() => { 14 | spanEl.remove(); 15 | }, 3000); 16 | }); 17 | -------------------------------------------------------------------------------- /projects/heart-trail-animation/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | height: 100vh; 4 | background-color: black; 5 | overflow: hidden; 6 | } 7 | 8 | span { 9 | background: url("https://cdn4.iconfinder.com/data/icons/general-office/91/General_Office_54-512.png"); 10 | width: 100px; 11 | height: 100px; 12 | position: absolute; 13 | pointer-events: none; 14 | background-size: cover; 15 | left: 50%; 16 | top: 50%; 17 | transform: translate(-50%, -50%); 18 | animation: animate 6s linear; 19 | } 20 | 21 | @keyframes animate { 22 | 0% { 23 | transform: translate(-50%, -50%); 24 | opacity: 1; 25 | filter: hue-rotate(0); 26 | } 27 | 100% { 28 | transform: translate(-50%, -5000%); 29 | opacity: 0; 30 | filter: hue-rotate(720deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /projects/image-search-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Image Search App 8 | 9 | 10 | 11 |

Image Search App

12 |
13 | 14 | 15 |
16 |
17 | 53 |
54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /projects/image-search-app/index.js: -------------------------------------------------------------------------------- 1 | const accessKey = "RZEIOVfPhS7vMLkFdd2TSKGFBS4o9_FmcV1Nje3FSjw"; 2 | 3 | const formEl = document.querySelector("form"); 4 | const searchInputEl = document.getElementById("search-input"); 5 | const searchResultsEl = document.querySelector(".search-results"); 6 | const showMoreButtonEl = document.getElementById("show-more-button"); 7 | 8 | let inputData = ""; 9 | let page = 1; 10 | 11 | async function searchImages() { 12 | inputData = searchInputEl.value; 13 | const url = `https://api.unsplash.com/search/photos?page=${page}&query=${inputData}&client_id=${accessKey}`; 14 | 15 | const response = await fetch(url); 16 | const data = await response.json(); 17 | if (page === 1) { 18 | searchResultsEl.innerHTML = ""; 19 | } 20 | 21 | const results = data.results; 22 | 23 | results.map((result) => { 24 | const imageWrapper = document.createElement("div"); 25 | imageWrapper.classList.add("search-result"); 26 | const image = document.createElement("img"); 27 | image.src = result.urls.small; 28 | image.alt = result.alt_description; 29 | const imageLink = document.createElement("a"); 30 | imageLink.href = result.links.html; 31 | imageLink.target = "_blank"; 32 | imageLink.textContent = result.alt_description; 33 | 34 | imageWrapper.appendChild(image); 35 | imageWrapper.appendChild(imageLink); 36 | searchResultsEl.appendChild(imageWrapper); 37 | }); 38 | 39 | page++; 40 | 41 | if (page > 1) { 42 | showMoreButtonEl.style.display = "block"; 43 | } 44 | } 45 | 46 | formEl.addEventListener("submit", (event) => { 47 | event.preventDefault(); 48 | page = 1; 49 | searchImages(); 50 | }); 51 | 52 | showMoreButtonEl.addEventListener("click", () => { 53 | searchImages(); 54 | }); 55 | -------------------------------------------------------------------------------- /projects/image-search-app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f9f9f9; 3 | font-family: Arial, Helvetica, sans-serif; 4 | line-height: 1.6; 5 | margin: 0; 6 | } 7 | 8 | h1 { 9 | font-size: 36px; 10 | font-weight: bold; 11 | text-align: center; 12 | margin-top: 40px; 13 | margin-bottom: 60px; 14 | } 15 | 16 | form { 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | margin-bottom: 60px; 21 | } 22 | 23 | #search-input { 24 | width: 60%; 25 | max-width: 400px; 26 | padding: 10px 20px; 27 | border: none; 28 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 29 | border-radius: 5px; 30 | font-size: 18px; 31 | color: #333; 32 | } 33 | 34 | #search-button { 35 | padding: 10px 20px; 36 | background-color: #4caf50; 37 | color: white; 38 | border: none; 39 | font-size: 18px; 40 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 41 | cursor: pointer; 42 | border-radius: 5px; 43 | transition: background-color 0.3s ease-in-out; 44 | } 45 | 46 | #search-button:hover { 47 | background-color: #3e8e41; 48 | } 49 | 50 | .search-results { 51 | display: flex; 52 | flex-wrap: wrap; 53 | justify-content: space-between; 54 | max-width: 1200px; 55 | margin: 0 auto; 56 | padding: 20px; 57 | } 58 | 59 | .search-result { 60 | margin-bottom: 60px; 61 | width: 30%; 62 | border-radius: 5px; 63 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); 64 | overflow: hidden; 65 | } 66 | 67 | .search-result:hover img { 68 | transform: scale(1.05); 69 | } 70 | 71 | .search-result img { 72 | width: 100%; 73 | height: 200px; 74 | object-fit: cover; 75 | transition: transform 0.3s ease-in-out; 76 | } 77 | .search-result a { 78 | padding: 10px; 79 | display: block; 80 | color: #333; 81 | text-decoration: none; 82 | transition: background-color 0.3s ease-in-out; 83 | } 84 | 85 | .search-result:hover a { 86 | background-color: rgba(0, 0, 0, 0.1); 87 | } 88 | 89 | #show-more-button { 90 | background-color: #008cba; 91 | border: none; 92 | color: white; 93 | padding: 10px 20px; 94 | display: block; 95 | margin: 20px auto; 96 | text-align: center; 97 | border-radius: 5px; 98 | cursor: pointer; 99 | transition: background-color 0.3s ease-in-out; 100 | display: none; 101 | } 102 | 103 | #show-more-button:hover { 104 | background-color: #0077b5; 105 | } 106 | 107 | @media screen and (max-width: 768px) { 108 | .search-result { 109 | width: 45%; 110 | } 111 | } 112 | @media screen and (max-width: 480px) { 113 | .search-result { 114 | width: 100%; 115 | } 116 | 117 | form { 118 | flex-direction: column; 119 | } 120 | 121 | #search-input { 122 | margin-bottom: 20px; 123 | width: 85%; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /projects/image-slider/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Image Slider 8 | 15 | 16 | 17 | 18 |
19 |
20 | image 21 | image 22 | image 23 | image 24 | image 25 |
26 | 27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /projects/image-slider/index.js: -------------------------------------------------------------------------------- 1 | const nextEl = document.querySelector(".next"); 2 | 3 | const prevEl = document.querySelector(".prev"); 4 | 5 | const imgsEl = document.querySelectorAll("img"); 6 | 7 | const imageContainerEl = document.querySelector(".image-container"); 8 | 9 | let currentImg = 1; 10 | 11 | let timeout; 12 | 13 | nextEl.addEventListener("click", () => { 14 | currentImg++; 15 | clearTimeout(timeout); 16 | updateImg(); 17 | }); 18 | 19 | prevEl.addEventListener("click", () => { 20 | currentImg--; 21 | clearTimeout(timeout); 22 | updateImg(); 23 | }); 24 | 25 | updateImg(); 26 | 27 | function updateImg() { 28 | if (currentImg > imgsEl.length) { 29 | currentImg = 1; 30 | } else if (currentImg < 1) { 31 | currentImg = imgsEl.length; 32 | } 33 | imageContainerEl.style.transform = `translateX(-${(currentImg - 1) * 500}px)`; 34 | timeout = setTimeout(() => { 35 | currentImg++; 36 | updateImg(); 37 | }, 3000); 38 | } 39 | -------------------------------------------------------------------------------- /projects/image-slider/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: wheat; 8 | } 9 | 10 | .slider-container { 11 | position: relative; 12 | width: 500px; 13 | overflow: hidden; 14 | height: 300px; 15 | border-radius: 10px; 16 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 17 | } 18 | 19 | .image-container { 20 | display: flex; 21 | transition: transform 0.4s ease-in-out; 22 | } 23 | 24 | .btn { 25 | position: absolute; 26 | top: 50%; 27 | transform: translateY(-50%); 28 | color: white; 29 | font-size: 20px; 30 | opacity: 0.5; 31 | cursor: pointer; 32 | } 33 | 34 | .btn.prev { 35 | left: 10px; 36 | } 37 | 38 | .btn.next { 39 | right: 10px; 40 | } 41 | 42 | .btn:hover { 43 | opacity: 1; 44 | } 45 | -------------------------------------------------------------------------------- /projects/loading-bar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Loading Bar 8 | 9 | 10 | 11 |
12 |

Loading

13 |
0%
14 |
15 |
16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /projects/loading-bar/index.js: -------------------------------------------------------------------------------- 1 | const counterEl = document.querySelector(".counter"); 2 | 3 | const barEl = document.querySelector(".loading-bar-front"); 4 | 5 | let idx = 0; 6 | 7 | updateNum(); 8 | 9 | function updateNum() { 10 | counterEl.innerText = idx + "%"; 11 | barEl.style.width = idx + "%"; 12 | idx++; 13 | if (idx < 101) { 14 | setTimeout(updateNum, 20); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /projects/loading-bar/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: black; 8 | color: lightgray; 9 | font-family: cursive; 10 | } 11 | 12 | .container { 13 | text-align: center; 14 | width: 400px; 15 | position: relative; 16 | } 17 | 18 | .counter { 19 | font-size: 40px; 20 | } 21 | 22 | .loading-bar-back { 23 | position: absolute; 24 | height: 8px; 25 | background-color: lightgray; 26 | width: 100%; 27 | border-radius: 5px; 28 | border: none; 29 | } 30 | 31 | .loading-bar-front { 32 | position: absolute; 33 | height: 8px; 34 | background-color: orangered; 35 | width: 0%; 36 | border-radius: 5px; 37 | border: none; 38 | } 39 | -------------------------------------------------------------------------------- /projects/loan-calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Loan Calculator 8 | 9 | 10 | 11 |
12 |

Loan Calculator

13 |

Loan Amount $ 14 | 15 |

16 |

Interest Rate % 17 | 18 |

19 |

Months to pay 20 | 21 |

22 |

Monthly Payment:

23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/loan-calculator/index.js: -------------------------------------------------------------------------------- 1 | function calculateLoan() { 2 | loanAmountValue = document.getElementById("loan-amount").value; 3 | 4 | interestRateValue = document.getElementById("interest-rate").value; 5 | 6 | MonthsToPayValue = document.getElementById("months-to-pay").value; 7 | 8 | interest = (loanAmountValue * (interestRateValue * 0.01)) / MonthsToPayValue; 9 | 10 | monthlyPayment = (loanAmountValue / MonthsToPayValue + interest).toFixed(2); 11 | 12 | document.getElementById( 13 | "payment" 14 | ).innerHTML = `Monthly Payment: ${monthlyPayment}`; 15 | } 16 | -------------------------------------------------------------------------------- /projects/loan-calculator/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | padding: 0; 3 | margin: 0; 4 | display: flex; 5 | height: 100vh; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: 'Courier New', Courier, monospace; 9 | } 10 | 11 | .container{ 12 | background: darkcyan; 13 | color: aliceblue; 14 | padding: 20px; 15 | border-radius: 10px; 16 | } 17 | 18 | .input{ 19 | width: 100%; 20 | font-size: 20px; 21 | height: 30px; 22 | } 23 | 24 | .payment{ 25 | font-weight: 600; 26 | font-size: 20px; 27 | } -------------------------------------------------------------------------------- /projects/mini-calendar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mini Calendar 8 | 9 | 10 | 11 |
12 |

April

13 |

Friday

14 |

20

15 |

2020

16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /projects/mini-calendar/index.js: -------------------------------------------------------------------------------- 1 | const monthNameEl = document.getElementById("month-name"); 2 | const dayNameEl = document.getElementById("day-name"); 3 | const dayNumEl = document.getElementById("day-number"); 4 | const yearEl = document.getElementById("year"); 5 | 6 | const date = new Date(); 7 | const month = date.getMonth(); 8 | monthNameEl.innerText = date.toLocaleString("en", { 9 | month: "long", 10 | }); 11 | 12 | dayNameEl.innerText = date.toLocaleString("en", { 13 | weekday: "long", 14 | }); 15 | 16 | dayNumEl.innerText = date.getDate(); 17 | 18 | yearEl.innerText = date.getFullYear(); 19 | -------------------------------------------------------------------------------- /projects/mini-calendar/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | font-family: cursive; 8 | background-color: slateblue; 9 | } 10 | 11 | .calendar-container { 12 | background-color: white; 13 | width: 300px; 14 | text-align: center; 15 | border-radius: 10px; 16 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 17 | overflow: hidden; 18 | } 19 | 20 | .month-name { 21 | margin: 0; 22 | background-color: orangered; 23 | color: white; 24 | padding: 10px; 25 | font-size: 30px; 26 | font-weight: bold; 27 | } 28 | 29 | .day-name { 30 | font-size: 20px; 31 | color: darkgray; 32 | } 33 | 34 | .day-number { 35 | font-size: 80px; 36 | margin: 0; 37 | font-weight: bold; 38 | } 39 | 40 | .year { 41 | margin: 20px 0; 42 | font-size: 20px; 43 | color: darkgray; 44 | font-weight: 500; 45 | } 46 | -------------------------------------------------------------------------------- /projects/month-calender/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Month Calender 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |

16 |

17 |
18 |
19 |
20 |
Mon
21 |
Tue
22 |
Wed
23 |
Thu
24 |
Fri
25 |
Sat
26 |
Sun
27 |
28 |
29 |
30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/month-calender/index.js: -------------------------------------------------------------------------------- 1 | const monthEl = document.querySelector(".date h1"); 2 | const fullDateEl = document.querySelector(".date p"); 3 | const daysEl = document.querySelector(".days"); 4 | 5 | const monthInx = new Date().getMonth(); 6 | const lastDay = new Date(new Date().getFullYear(), monthInx + 1, 0).getDate(); 7 | const firstDay = new Date(new Date().getFullYear(), monthInx, 1).getDay() - 1; 8 | 9 | 10 | const months = [ 11 | "January", 12 | "February", 13 | "March", 14 | "April", 15 | "May", 16 | "June", 17 | "July", 18 | "August", 19 | "September", 20 | "October", 21 | "November", 22 | "December", 23 | ]; 24 | 25 | monthEl.innerText = months[monthInx]; 26 | fullDateEl.innerText = new Date().toDateString(); 27 | 28 | let days = ""; 29 | 30 | for (let i = firstDay; i > 0; i--) { 31 | days += `
`; 32 | } 33 | for (let i = 1; i <= lastDay; i++) { 34 | if (i === new Date().getDate()) { 35 | days += `
${i}
`; 36 | } else { 37 | days += `
${i}
`; 38 | } 39 | } 40 | 41 | daysEl.innerHTML = days; 42 | -------------------------------------------------------------------------------- /projects/month-calender/style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | box-sizing: border-box; 6 | } 7 | 8 | .container{ 9 | width: 100%; 10 | height: 100vh; 11 | background-color: salmon; 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | } 16 | 17 | .calender{ 18 | background-color: black; 19 | color: lightgray; 20 | width: 450px; 21 | height: 520px; 22 | border-radius: 10px; 23 | box-shadow: 4px 4px 8px rgba(0, 0, 0, .4); 24 | } 25 | 26 | .month{ 27 | width: 100%; 28 | height: 120px; 29 | background-color: lightseagreen; 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | text-align: center; 34 | border-radius: 10px 10px 0 0; 35 | } 36 | 37 | .month h1{ 38 | font-size: 30px; 39 | font-weight: 400; 40 | text-transform: uppercase; 41 | } 42 | 43 | .month p{ 44 | font-size: 16px; 45 | } 46 | 47 | .weekdays{ 48 | width: 100%; 49 | height: 50px; 50 | display: flex; 51 | } 52 | 53 | .weekdays div{ 54 | font-size: 15px; 55 | font-weight: bold; 56 | letter-spacing: 1px; 57 | width: 100%; 58 | display: flex; 59 | align-items: center; 60 | justify-content: center; 61 | } 62 | 63 | .days{ 64 | width: 100%; 65 | display: flex; 66 | flex-wrap: wrap; 67 | padding: 2px; 68 | } 69 | 70 | .days div{ 71 | font-size: 14px; 72 | margin: 3px; 73 | width: 57.5px; 74 | height: 50px; 75 | display: flex; 76 | justify-content: center; 77 | align-items: center; 78 | } 79 | 80 | .days div:hover:not(.empty){ 81 | border: 2px solid gray; 82 | cursor: pointer; 83 | } 84 | 85 | .today{ 86 | background-color: lightseagreen; 87 | } -------------------------------------------------------------------------------- /projects/mouse-event/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mouse Event 8 | 9 | 10 | 11 |
12 |
13 | 20 14 |

Mouse X Prosition(px)

15 |
16 |
17 | 20 18 |

Mouse Y Prosition(px)

19 |
20 |
21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/mouse-event/index.js: -------------------------------------------------------------------------------- 1 | const containerEl = document.querySelector(".container"); 2 | 3 | window.addEventListener("mousemove", (event) => { 4 | containerEl.innerHTML = ` 5 |
6 | ${event.clientX} 7 |

Mouse X Prosition(px)

8 |
9 |
10 | ${event.clientY} 11 |

Mouse Y Prosition(px)

12 |
13 | `; 14 | }); 15 | -------------------------------------------------------------------------------- /projects/mouse-event/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: darkblue; 8 | color: white; 9 | font-family: cursive; 10 | } 11 | 12 | .container { 13 | display: flex; 14 | text-align: center; 15 | } 16 | 17 | .mouse-event { 18 | border: solid 1px lightgray; 19 | margin: 40px; 20 | min-width: 180px; 21 | min-height: 100px; 22 | position: relative; 23 | justify-content: center; 24 | align-items: center; 25 | display: flex; 26 | font-size: 30px; 27 | } 28 | 29 | .mouse-event h4 { 30 | position: absolute; 31 | top: -50px; 32 | font-size: 14px; 33 | left: 50%; 34 | transform: translateX(-50%); 35 | white-space: nowrap; 36 | font-weight: 100; 37 | color: lightgray; 38 | } 39 | 40 | @media (max-width: 500px) { 41 | .container { 42 | flex-direction: column; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /projects/multiplication-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Multiplication App 8 | 9 | 10 | 11 |
12 |

score: 0

13 |

What is 1 multiply by 1?

14 | 22 | 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/multiplication-app/index.js: -------------------------------------------------------------------------------- 1 | const num1 = Math.ceil(Math.random() * 10); 2 | const num2 = Math.ceil(Math.random() * 10); 3 | 4 | const questionEl = document.getElementById("question"); 5 | 6 | const inputEl = document.getElementById("input"); 7 | 8 | const formEl = document.getElementById("form"); 9 | 10 | const scoreEl = document.getElementById("score"); 11 | 12 | let score = JSON.parse(localStorage.getItem("score")); 13 | 14 | if (!score) { 15 | score = 0; 16 | } 17 | 18 | scoreEl.innerText = `score: ${score}`; 19 | 20 | questionEl.innerText = `What is ${num1} multiply by ${num2}?`; 21 | 22 | const correctAns = num1 * num2; 23 | 24 | formEl.addEventListener("submit", () => { 25 | const userAns = +inputEl.value; 26 | if (userAns === correctAns) { 27 | score++; 28 | updateLocalStorage(); 29 | } else { 30 | score--; 31 | updateLocalStorage(); 32 | } 33 | }); 34 | 35 | function updateLocalStorage() { 36 | localStorage.setItem("score", JSON.stringify(score)); 37 | } 38 | -------------------------------------------------------------------------------- /projects/multiplication-app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | text-align: center; 8 | background-color: yellow; 9 | font-family: cursive; 10 | } 11 | 12 | .form { 13 | background-color: white; 14 | padding: 20px; 15 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 16 | border-radius: 10px; 17 | margin: 10px; 18 | } 19 | 20 | .input { 21 | display: block; 22 | width: 100%; 23 | box-sizing: border-box; 24 | font-size: 30px; 25 | text-align: center; 26 | padding: 10px; 27 | border: solid 4px green; 28 | color: green; 29 | } 30 | 31 | .input::placeholder { 32 | color: lightgray; 33 | font-family: cursive; 34 | } 35 | 36 | .btn { 37 | background-color: green; 38 | color: white; 39 | border: none; 40 | display: block; 41 | width: 100%; 42 | padding: 10px; 43 | font-size: 20px; 44 | font-family: cursive; 45 | margin: 20px 0; 46 | border-radius: 5px; 47 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); 48 | cursor: pointer; 49 | } 50 | 51 | .btn:hover { 52 | filter: brightness(0.9); 53 | } 54 | 55 | .score { 56 | color: green; 57 | text-align: right; 58 | } 59 | -------------------------------------------------------------------------------- /projects/music-player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Music Player 5 | 6 | 7 | 8 |
9 |

Music Player

10 |
11 | 12 |
13 | 14 | 15 |
16 |
17 |
18 |
19 |
20 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /projects/music-player/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/music-player/pause.png -------------------------------------------------------------------------------- /projects/music-player/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/music-player/play.png -------------------------------------------------------------------------------- /projects/music-player/script.js: -------------------------------------------------------------------------------- 1 | const playlist = [ 2 | { title: "Song 1", src: "songs/song1.m4a" }, 3 | { title: "Song 2", src: "songs/song2.m4a" }, 4 | { title: "Song 3", src: "songs/song3.m4a" }, 5 | ]; 6 | 7 | const links = document.querySelectorAll(".playlist__item a"); 8 | 9 | links.forEach((link) => { 10 | link.addEventListener("click", function (e) { 11 | e.preventDefault(); 12 | const source = this.getAttribute("data-src"); 13 | document.querySelector("#player").setAttribute("src", source); 14 | playSong(); 15 | 16 | // Remove active class from all links 17 | links.forEach((link) => { 18 | link.classList.remove("active-song"); 19 | }); 20 | 21 | // Add active class to clicked link 22 | this.classList.add("active-song"); 23 | }); 24 | }); 25 | 26 | function playSong() { 27 | const player = document.querySelector("#player"); 28 | const playButton = document.querySelector(".player__button--play"); 29 | const pauseButton = document.querySelector(".player__button--pause"); 30 | const progressBar = document.querySelector(".player__progress-bar"); 31 | 32 | if (player.paused) { 33 | player.play(); 34 | playButton.classList.remove("active"); 35 | pauseButton.classList.add("active"); 36 | } else { 37 | player.pause(); 38 | playButton.classList.add("active"); 39 | pauseButton.classList.remove("active"); 40 | } 41 | 42 | player.addEventListener("timeupdate", function () { 43 | const progress = (player.currentTime / player.duration) * 100; 44 | progressBar.style.width = `${progress}%`; 45 | }); 46 | 47 | progressBar.addEventListener("click", function (e) { 48 | const progressWidth = this.offsetWidth; 49 | const clickedWidth = e.offsetX; 50 | const percent = (clickedWidth / progressWidth) * 100; 51 | player.currentTime = (player.duration / 100) * percent; 52 | progressBar.style.width = `${percent}%`; 53 | }); 54 | } 55 | 56 | function playFirstSong() { 57 | const firstSong = playlist[0].src; 58 | document.querySelector("#player").setAttribute("src", firstSong); 59 | playSong(); 60 | } 61 | 62 | const playButton = document.querySelector(".player__button--play"); 63 | const pauseButton = document.querySelector(".player__button--pause"); 64 | 65 | playButton.addEventListener("click", function () { 66 | const player = document.querySelector("#player"); 67 | player.play(); 68 | playButton.classList.remove("active"); 69 | pauseButton.classList.add("active"); 70 | }); 71 | 72 | pauseButton.addEventListener("click", function () { 73 | const player = document.querySelector("#player"); 74 | player.pause(); 75 | playButton.classList.add("active"); 76 | pauseButton.classList.remove("active"); 77 | }); 78 | 79 | const player = document.querySelector("#player"); 80 | player.addEventListener("play", function () { 81 | playButton.classList.remove("active"); 82 | pauseButton.classList.add("active"); 83 | }); 84 | 85 | player.addEventListener("pause", function () { 86 | playButton.classList.add("active"); 87 | pauseButton.classList.remove("active"); 88 | }); 89 | 90 | playFirstSong(); 91 | -------------------------------------------------------------------------------- /projects/music-player/songs/song1.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/music-player/songs/song1.m4a -------------------------------------------------------------------------------- /projects/music-player/songs/song2.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/music-player/songs/song2.m4a -------------------------------------------------------------------------------- /projects/music-player/songs/song3.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/music-player/songs/song3.m4a -------------------------------------------------------------------------------- /projects/music-player/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | font-family: Arial, sans-serif; 9 | background-color: #f2f2f2; 10 | } 11 | 12 | .container { 13 | max-width: 600px; 14 | margin: 0 auto; 15 | padding: 0 20px; 16 | } 17 | 18 | .title { 19 | text-align: center; 20 | margin-top: 50px; 21 | margin-bottom: 50px; 22 | } 23 | 24 | .player { 25 | margin-bottom: 50px; 26 | } 27 | 28 | .player__controls { 29 | display: flex; 30 | justify-content: center; 31 | margin-bottom: 20px; 32 | } 33 | 34 | .player__button { 35 | width: 50px; 36 | height: 50px; 37 | background-color: #fff; 38 | border: none; 39 | cursor: pointer; 40 | margin-right: 10px; 41 | background-image: url("play.png"); 42 | background-repeat: no-repeat; 43 | background-position: center; 44 | background-size: 60%; 45 | } 46 | 47 | .player__button--pause { 48 | background-image: url("pause.png"); 49 | } 50 | 51 | .player__button.active { 52 | background-color: #0074d9; 53 | color: #fff; 54 | } 55 | 56 | .player__progress { 57 | height: 5px; 58 | background-color: #f5f5f5; 59 | position: relative; 60 | } 61 | 62 | .player__progress-bar { 63 | position: absolute; 64 | top: 0; 65 | left: 0; 66 | height: 100%; 67 | background-color: #0074d9; 68 | width: 0%; 69 | } 70 | 71 | .playlist__item { 72 | margin-bottom: 10px; 73 | } 74 | 75 | .playlist__item a { 76 | display: block; 77 | padding: 10px; 78 | background-color: #fff; 79 | color: #333; 80 | text-decoration: none; 81 | } 82 | 83 | .playlist__item a:hover { 84 | background-color: #f5f5f5; 85 | } 86 | 87 | .playlist__item a.active-song { 88 | background-color: #0074d9; 89 | color: #fff; 90 | } 91 | -------------------------------------------------------------------------------- /projects/navbar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Navbar project 8 | 14 | 15 | 16 | 17 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /projects/navbar/index.js: -------------------------------------------------------------------------------- 1 | const bar = document.querySelector(".fa-bars"); 2 | const menu = document.querySelector(".menu"); 3 | 4 | bar.addEventListener("click", () => { 5 | menu.classList.toggle("show-menu"); 6 | }); 7 | -------------------------------------------------------------------------------- /projects/navbar/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background: #f1f5f8; 6 | line-height: 2.2; 7 | font-size: 0.875rem; 8 | } 9 | 10 | ul { 11 | list-style-type: none; 12 | } 13 | 14 | a { 15 | text-decoration: none; 16 | } 17 | 18 | nav { 19 | background: white; 20 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); 21 | } 22 | 23 | .fa-bars { 24 | font-size: 1.5rem; 25 | color: #e94949; 26 | cursor: pointer; 27 | } 28 | 29 | .fa-bars:hover { 30 | color: black; 31 | } 32 | 33 | .menu a { 34 | color: grey; 35 | letter-spacing: 0.1rem; 36 | display: block; 37 | padding: 0.5rem 1rem; 38 | transition: all 0.3s linear; 39 | } 40 | 41 | .menu a:hover { 42 | background: #f8a5a5; 43 | color: #e94949; 44 | padding-left: 1.5rem; 45 | } 46 | 47 | .menu { 48 | height: 0; 49 | overflow: hidden; 50 | transition: all 0.3s linear; 51 | } 52 | 53 | .show-menu { 54 | height: 10rem; 55 | } 56 | 57 | .nav-header { 58 | display: flex; 59 | align-items: center; 60 | justify-content: space-between; 61 | padding: 1rem; 62 | } 63 | 64 | @media (min-width: 800px) { 65 | .nav-main { 66 | max-width: 1170px; 67 | margin: 0 auto; 68 | display: flex; 69 | align-items: center; 70 | justify-content: space-between; 71 | padding: 1rem; 72 | } 73 | 74 | .nav-header { 75 | padding: 0; 76 | } 77 | .fa-bars { 78 | display: none; 79 | } 80 | 81 | .menu { 82 | height: auto; 83 | display: flex; 84 | } 85 | 86 | .menu a { 87 | padding: 0; 88 | margin: 0 0.5rem; 89 | } 90 | .menu a:hover { 91 | padding: 0; 92 | background: transparent; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /projects/new-year-countdown/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | New Year Countdown 8 | 9 | 10 | 11 |

Countdown to New Year

12 |
2024
13 |
14 |
00
15 |
00
16 |
00
17 |
00
18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /projects/new-year-countdown/index.js: -------------------------------------------------------------------------------- 1 | const dayEl = document.getElementById("day"); 2 | const hourEl = document.getElementById("hour"); 3 | const minuteEl = document.getElementById("minute"); 4 | const secondEl = document.getElementById("second"); 5 | 6 | const newYearTime = new Date("Jan 1, 2024 00:00:00").getTime(); 7 | 8 | updateCountdown(); 9 | 10 | function updateCountdown() { 11 | const now = new Date().getTime(); 12 | const gap = newYearTime - now; 13 | 14 | const second = 1000; 15 | const minute = second * 60; 16 | const hour = minute * 60; 17 | const day = hour * 24; 18 | 19 | const d = Math.floor(gap / day); 20 | const h = Math.floor((gap % day) / hour); 21 | const m = Math.floor((gap % hour) / minute); 22 | const s = Math.floor((gap % minute) / second); 23 | dayEl.innerText = d; 24 | hourEl.innerText = h; 25 | minuteEl.innerText = m; 26 | secondEl.innerText = s; 27 | setTimeout(updateCountdown, 1000) 28 | } 29 | -------------------------------------------------------------------------------- /projects/new-year-countdown/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | height: 100vh; 7 | justify-content: center; 8 | font-family: cursive; 9 | background-color: slateblue; 10 | overflow: hidden; 11 | } 12 | 13 | h2 { 14 | color: white; 15 | text-align: center; 16 | text-transform: uppercase; 17 | letter-spacing: 4px; 18 | } 19 | 20 | .year { 21 | font-size: 5em; 22 | color: white; 23 | font-weight: bold; 24 | } 25 | 26 | .countdown { 27 | margin: 30px; 28 | background-color: rgba(0, 0, 0, 0.1); 29 | width: 100%; 30 | color: white; 31 | height: 120px; 32 | display: flex; 33 | justify-content: center; 34 | align-items: center; 35 | } 36 | 37 | .countdown div { 38 | margin: 0 15px; 39 | font-size: 2.5em; 40 | font-weight: 500; 41 | margin-top: -25px; 42 | position: relative; 43 | text-align: center; 44 | width: 100px; 45 | } 46 | 47 | .countdown div::before { 48 | content: ""; 49 | position: absolute; 50 | bottom: -30px; 51 | left: 0; 52 | font-size: 0.35em; 53 | line-height: 35px; 54 | text-transform: uppercase; 55 | letter-spacing: 1px; 56 | font-weight: 500; 57 | width: 100%; 58 | height: 35px; 59 | } 60 | 61 | .countdown #day::before { 62 | content: "Days"; 63 | } 64 | .countdown #hour::before { 65 | content: "Hours"; 66 | } 67 | .countdown #minute::before { 68 | content: "Minutes"; 69 | } 70 | .countdown #second::before { 71 | content: "Seconds"; 72 | } 73 | -------------------------------------------------------------------------------- /projects/note-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |

Note App

12 |

Double click on a note to remove it

13 |
14 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /projects/note-app/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const appEl = document.getElementById("app"); 3 | 4 | getNotes().forEach((note) => { 5 | const noteEl = createNoteEl(note.id, note.content); 6 | appEl.insertBefore(noteEl, btnEl); 7 | }); 8 | 9 | function createNoteEl(id, content) { 10 | const element = document.createElement("textarea"); 11 | element.classList.add("note"); 12 | element.placeholder = "Empty Note"; 13 | element.value = content; 14 | 15 | element.addEventListener("dblclick", () => { 16 | const warning = confirm("Do you want to delete this note?"); 17 | if (warning) { 18 | deleteNote(id, element); 19 | } 20 | }); 21 | 22 | element.addEventListener("input", () => { 23 | updateNote(id, element.value); 24 | }); 25 | 26 | return element; 27 | } 28 | 29 | function deleteNote(id, element) { 30 | const notes = getNotes().filter((note)=>note.id != id) 31 | saveNote(notes) 32 | appEl.removeChild(element) 33 | } 34 | 35 | function updateNote(id, content) { 36 | const notes = getNotes(); 37 | const target = notes.filter((note) => note.id == id)[0]; 38 | target.content = content; 39 | saveNote(notes); 40 | } 41 | 42 | function addNote() { 43 | const notes = getNotes(); 44 | const noteObj = { 45 | id: Math.floor(Math.random() * 100000), 46 | content: "", 47 | }; 48 | const noteEl = createNoteEl(noteObj.id, noteObj.content); 49 | appEl.insertBefore(noteEl, btnEl); 50 | 51 | notes.push(noteObj); 52 | 53 | saveNote(notes); 54 | } 55 | 56 | function saveNote(notes) { 57 | localStorage.setItem("note-app", JSON.stringify(notes)); 58 | } 59 | 60 | function getNotes() { 61 | return JSON.parse(localStorage.getItem("note-app") || "[]"); 62 | } 63 | 64 | btnEl.addEventListener("click", addNote); 65 | -------------------------------------------------------------------------------- /projects/note-app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: linear-gradient(to left, lightblue, lightgreen); 4 | font-family: "Courier New", Courier, monospace; 5 | } 6 | 7 | .heading { 8 | color: darkblue; 9 | text-align: center; 10 | padding-top: 10px; 11 | font-size: 35px; 12 | } 13 | 14 | .info-text { 15 | text-align: center; 16 | color: darkblue; 17 | font-size: 18px; 18 | } 19 | 20 | .app { 21 | display: grid; 22 | grid-template-columns: repeat(auto-fill, 300px); 23 | gap: 40px; 24 | justify-content: center; 25 | padding: 50px; 26 | } 27 | 28 | .note { 29 | padding: 17px; 30 | border-radius: 15px; 31 | resize: none; 32 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); 33 | font-size: 18px; 34 | height: 200px; 35 | color: darkblue; 36 | border: none; 37 | outline: none; 38 | background: rgba(255, 255, 255, 0.1); 39 | box-sizing: border-box; 40 | } 41 | 42 | .note::placeholder { 43 | color: gray; 44 | opacity: 30%; 45 | } 46 | 47 | .note:hover, 48 | .note:focus { 49 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); 50 | transition: all 300ms ease; 51 | } 52 | 53 | .btn{ 54 | height: 200px; 55 | border-color: rgba(255, 255, 255, 0.37); 56 | background: rgba(255, 255, 255, 0.27); 57 | border-radius: 15px; 58 | font-size: 70px; 59 | font-weight: 700; 60 | color: rgba(0, 0, 0, 0.3); 61 | cursor: pointer; 62 | } 63 | 64 | .btn:hover{ 65 | background: rgba(255, 255, 255, 0.55); 66 | color: rgba(0, 0, 0, 0.6); 67 | transition: all 300ms ease; 68 | } 69 | -------------------------------------------------------------------------------- /projects/photo-gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Photo Gallery 8 | 9 | 10 | 11 |
12 |

Photo Gallery

13 |

Enter the number of photos

14 | 22 | Error Message 23 | 24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /projects/photo-gallery/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const errorMessageEl = document.getElementById("errorMessage"); 3 | const galleryEl = document.getElementById("gallery"); 4 | 5 | async function fetchImage() { 6 | const inputValue = document.getElementById("input").value; 7 | 8 | if (inputValue > 10 || inputValue < 1) { 9 | errorMessageEl.style.display = "block"; 10 | errorMessageEl.innerText = "Number should be between 0 and 11"; 11 | return; 12 | } 13 | 14 | imgs = ""; 15 | 16 | try { 17 | btnEl.style.display = "none"; 18 | const loading = ``; 19 | galleryEl.innerHTML = loading; 20 | await fetch( 21 | `https://api.unsplash.com/photos?per_page=${inputValue}&page=${Math.round( 22 | Math.random() * 1000 23 | )}&client_id=B8S3zB8gCPVCvzpAhCRdfXg_aki8PZM_q5pAyzDUvlc` 24 | ).then((res) => 25 | res.json().then((data) => { 26 | if (data) { 27 | data.forEach((pic) => { 28 | imgs += ` 29 | image 30 | `; 31 | galleryEl.style.display = "block"; 32 | galleryEl.innerHTML = imgs; 33 | btnEl.style.display = "block"; 34 | errorMessageEl.style.display = "none"; 35 | }); 36 | } 37 | }) 38 | ); 39 | } catch (error) { 40 | console.log(error); 41 | errorMessageEl.style.display = "block"; 42 | errorMessageEl.innerHTML = "An error happened, try again later"; 43 | btnEl.style.display = "block"; 44 | galleryEl.style.display = "none"; 45 | } 46 | } 47 | 48 | btnEl.addEventListener("click", fetchImage); 49 | -------------------------------------------------------------------------------- /projects/photo-gallery/spinner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/photo-gallery/styles.css: -------------------------------------------------------------------------------- 1 | 2 | body{ 3 | margin: 0; 4 | font-family: 'Courier New', Courier, monospace; 5 | background: linear-gradient(to bottom, lightgreen, lightblue); 6 | display: flex; 7 | min-height: 100vh; 8 | justify-content: center; 9 | align-items: center; 10 | text-align: center; 11 | } 12 | 13 | .container{ 14 | background-color: aliceblue; 15 | padding: 20px; 16 | border-radius: 5px; 17 | box-shadow: 0 10px 20px rgba(0,0,0,0.3); 18 | width: 90%; 19 | margin: 10px; 20 | display: flex; 21 | flex-direction: column; 22 | text-align: center; 23 | justify-content: center; 24 | align-items: center; 25 | } 26 | 27 | h2{ 28 | font-weight: 400; 29 | } 30 | 31 | .input{ 32 | padding: 20px 10px; 33 | font-size: 18px; 34 | background-color: white; 35 | border-radius: 5px; 36 | text-align: center; 37 | width: 100px; 38 | } 39 | 40 | .errorMessage{ 41 | color: red; 42 | font-weight: 600; 43 | margin: 10px; 44 | display: none; 45 | } 46 | 47 | .btn{ 48 | text-transform: uppercase; 49 | width: 250px; 50 | height: 45px; 51 | margin: 20px 0; 52 | font-size: 18px; 53 | border-radius: 5px; 54 | background-color: black; 55 | color: aliceblue; 56 | 57 | } 58 | 59 | .btn:hover{ 60 | color: aliceblue; 61 | background-color: green; 62 | cursor: pointer; 63 | transition: background-color 300ms ease-in-out; 64 | } 65 | .gallery img{ 66 | width: 400px; 67 | height: 250px; 68 | object-fit: cover; 69 | border-radius: 5px; 70 | margin: 5px; 71 | } 72 | 73 | .gallery{ 74 | display: none; 75 | } -------------------------------------------------------------------------------- /projects/pomodoro-timer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Pomodoro Timer 8 | 9 | 10 | 11 |
12 |

Pomodoro Timer

13 |

25:00

14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /projects/pomodoro-timer/index.js: -------------------------------------------------------------------------------- 1 | const startEl = document.getElementById("start"); 2 | const stopEl = document.getElementById("stop"); 3 | const resetEl = document.getElementById("reset"); 4 | const timerEl = document.getElementById("timer"); 5 | 6 | let interval; 7 | let timeLeft = 1500; 8 | 9 | function updateTimer() { 10 | let minutes = Math.floor(timeLeft / 60); 11 | let seconds = timeLeft % 60; 12 | let formattedTime = `${minutes.toString().padStart(2, "0")}:${seconds 13 | .toString() 14 | .padStart(2, "0")}`; 15 | 16 | timerEl.innerHTML = formattedTime; 17 | } 18 | 19 | function startTimer() { 20 | interval = setInterval(() => { 21 | timeLeft--; 22 | updateTimer(); 23 | if (timeLeft === 0) { 24 | clearInterval(interval); 25 | alert("Time's up!"); 26 | timeLeft = 1500; 27 | updateTimer(); 28 | } 29 | }, 1000); 30 | } 31 | function stopTimer() { 32 | clearInterval(interval); 33 | } 34 | function resetTimer() { 35 | clearInterval(interval); 36 | timeLeft = 1500; 37 | updateTimer(); 38 | } 39 | 40 | startEl.addEventListener("click", startTimer); 41 | stopEl.addEventListener("click", stopTimer); 42 | resetEl.addEventListener("click", resetTimer); 43 | -------------------------------------------------------------------------------- /projects/pomodoro-timer/style.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin: 0 auto; 3 | max-width: 400px; 4 | text-align: center; 5 | padding: 20px; 6 | font-family: "Roboto", sans-serif; 7 | } 8 | 9 | .title { 10 | font-size: 36px; 11 | margin-bottom: 10px; 12 | color: #2c3e50; 13 | } 14 | 15 | .timer { 16 | font-size: 72px; 17 | color: #2c3e50; 18 | } 19 | 20 | button { 21 | font-size: 18px; 22 | padding: 10px 20px; 23 | margin: 10px; 24 | color: white; 25 | 26 | border: none; 27 | border-radius: 4px; 28 | cursor: pointer; 29 | text-transform: uppercase; 30 | transition: opacity 0.3s ease-in-out; 31 | } 32 | 33 | button:hover { 34 | opacity: 0.7; 35 | } 36 | 37 | #start { 38 | background-color: #27ae60; 39 | } 40 | 41 | #stop { 42 | background-color: #c0392b; 43 | } 44 | 45 | #reset { 46 | background-color: #7f8c8d; 47 | } 48 | -------------------------------------------------------------------------------- /projects/profile-statistics/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Profile Statistics 8 | 15 | 16 | 17 | 18 |
19 | 20 |
15
21 |

Years Exprerience

22 |
23 |
24 | 25 |
260
26 |

Websites Made

27 |
28 |
29 | 30 |
27
31 |

Apps Made

32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /projects/profile-statistics/index.js: -------------------------------------------------------------------------------- 1 | const countersEl = document.querySelectorAll(".counter"); 2 | 3 | countersEl.forEach((counterEl) => { 4 | counterEl.innerText = "0"; 5 | incrementCounter(); 6 | function incrementCounter() { 7 | let currentNum = +counterEl.innerText; 8 | const dataCeil = counterEl.getAttribute("data-ceil"); 9 | const increment = dataCeil / 15; 10 | currentNum = Math.ceil(currentNum + increment); 11 | 12 | if (currentNum < dataCeil) { 13 | counterEl.innerText = currentNum; 14 | setTimeout(incrementCounter, 50); 15 | } else { 16 | counterEl.innerText = dataCeil; 17 | } 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /projects/profile-statistics/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | text-align: center; 8 | background-color: yellow; 9 | font-family: cursive; 10 | } 11 | 12 | .stats-container { 13 | margin: 20px; 14 | border: dotted green; 15 | min-width: 200px; 16 | height: 100px; 17 | position: relative; 18 | padding: 20px; 19 | } 20 | 21 | .stats-container h4 { 22 | position: absolute; 23 | bottom: 1px; 24 | left: 50%; 25 | transform: translateX(-50%); 26 | white-space: nowrap; 27 | } 28 | 29 | .icon { 30 | position: absolute; 31 | top: -30px; 32 | left: 50%; 33 | transform: translateX(-50%); 34 | } 35 | 36 | .counter { 37 | font-size: 50px; 38 | position: absolute; 39 | left: 50%; 40 | transform: translateX(-50%); 41 | color: green; 42 | } 43 | 44 | @media (max-width: 600px) { 45 | body { 46 | flex-direction: column; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /projects/q-and-a-section/app.js: -------------------------------------------------------------------------------- 1 | const questions = document.querySelectorAll(".question"); 2 | 3 | questions.forEach(function (question) { 4 | const btn = question.querySelector(".question-btn"); 5 | 6 | btn.addEventListener("click", function () { 7 | question.classList.toggle("show-text"); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /projects/random-color-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Random Color Generator 8 | 9 | 10 | 11 |

Random Color Generator

12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /projects/random-color-generator/index.js: -------------------------------------------------------------------------------- 1 | const containerEl = document.querySelector(".container"); 2 | 3 | for (let index = 0; index < 30; index++) { 4 | const colorContainerEl = document.createElement("div"); 5 | colorContainerEl.classList.add("color-container"); 6 | containerEl.appendChild(colorContainerEl); 7 | } 8 | 9 | const colorContainerEls = document.querySelectorAll(".color-container"); 10 | 11 | generateColors(); 12 | 13 | function generateColors() { 14 | colorContainerEls.forEach((colorContainerEl) => { 15 | const newColorCode = randomColor(); 16 | colorContainerEl.style.backgroundColor = "#" + newColorCode; 17 | colorContainerEl.innerText = "#" + newColorCode; 18 | }); 19 | } 20 | 21 | function randomColor() { 22 | const chars = "0123456789abcdef"; 23 | const colorCodeLength = 6; 24 | let colorCode = ""; 25 | for (let index = 0; index < colorCodeLength; index++) { 26 | const randomNum = Math.floor(Math.random() * chars.length); 27 | colorCode += chars.substring(randomNum, randomNum + 1); 28 | } 29 | return colorCode; 30 | } 31 | -------------------------------------------------------------------------------- /projects/random-color-generator/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: cursive; 4 | } 5 | 6 | h1 { 7 | text-align: center; 8 | } 9 | 10 | .container { 11 | display: flex; 12 | flex-wrap: wrap; 13 | justify-content: center; 14 | } 15 | 16 | .color-container { 17 | background-color: orange; 18 | width: 300px; 19 | height: 150px; 20 | color: white; 21 | margin: 5px; 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | font-size: 25px; 26 | text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); 27 | border: solid black 2px; 28 | border-radius: 10px; 29 | } 30 | -------------------------------------------------------------------------------- /projects/random-emoji/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Random Emoji 9 | 10 | 11 |

Random Emoji

12 |
13 | 14 |

Emoji Name

15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /projects/random-emoji/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const emojiNameEl = document.getElementById("emoji-name"); 3 | 4 | const emoji = []; 5 | 6 | async function getEmoji() { 7 | let response = await fetch( 8 | "https://emoji-api.com/emojis?access_key=773b58f681fb786fafdb8392e8b8a75ddc177fd1" 9 | ); 10 | 11 | data = await response.json(); 12 | 13 | for (let i = 0; i < 1500; i++) { 14 | emoji.push({ 15 | emojiName: data[i].character, 16 | emojiCode: data[i].unicodeName, 17 | }); 18 | } 19 | } 20 | 21 | getEmoji(); 22 | 23 | btnEl.addEventListener("click", () => { 24 | const randomNum = Math.floor(Math.random() * emoji.length); 25 | btnEl.innerText = emoji[randomNum].emojiName; 26 | emojiNameEl.innerText = emoji[randomNum].emojiCode; 27 | }); 28 | -------------------------------------------------------------------------------- /projects/random-emoji/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | padding: 0; 3 | margin: 0; 4 | background: salmon; 5 | display: flex; 6 | flex-direction: column; 7 | justify-content: center; 8 | height: 100vh; 9 | align-items: center; 10 | font-family: 'Courier New', Courier, monospace; 11 | } 12 | 13 | h2{ 14 | font-size: 2rem; 15 | color: aliceblue; 16 | } 17 | 18 | .section{ 19 | text-align: center; 20 | } 21 | 22 | .btn{ 23 | font-size: 5rem; 24 | border: none; 25 | background: rgb(255,255,255,.2); 26 | border-radius: 10px; 27 | padding: 15px; 28 | filter: grayscale(); 29 | transition: filter .2s ease-in-out; 30 | cursor: pointer; 31 | 32 | } 33 | 34 | .btn:hover{ 35 | filter: grayscale(0); 36 | } 37 | 38 | .emoji-name{ 39 | font-weight: 600; 40 | color: darkblue; 41 | } -------------------------------------------------------------------------------- /projects/random-password-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Random Password Generator 8 | 15 | 16 | 17 | 18 |
19 |

Random Password Generator

20 |
21 | 28 | 29 |
30 | 31 |
32 |
Password Copied
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /projects/random-password-generator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.querySelector(".btn"); 2 | const inputEl = document.getElementById("input"); 3 | const copyIconEl = document.querySelector(".fa-copy"); 4 | const alertContainerEl = document.querySelector(".alert-container"); 5 | 6 | btnEl.addEventListener("click", () => { 7 | createPassword(); 8 | }); 9 | 10 | copyIconEl.addEventListener("click", () => { 11 | copyPassword(); 12 | if (inputEl.value) { 13 | alertContainerEl.classList.remove("active"); 14 | setTimeout(() => { 15 | alertContainerEl.classList.add("active"); 16 | }, 2000); 17 | } 18 | }); 19 | 20 | function createPassword() { 21 | const chars = 22 | "0123456789abcdefghijklmnopqrstuvwxtz!@#$%^&*()_+?:{}[]ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 23 | const passwordLength = 14; 24 | let password = ""; 25 | for (let index = 0; index < passwordLength; index++) { 26 | const randomNum = Math.floor(Math.random() * chars.length); 27 | password += chars.substring(randomNum, randomNum + 1); 28 | } 29 | inputEl.value = password; 30 | alertContainerEl.innerText = password + " copied!"; 31 | } 32 | 33 | function copyPassword() { 34 | inputEl.select(); 35 | inputEl.setSelectionRange(0, 9999); 36 | navigator.clipboard.writeText(inputEl.value); 37 | } 38 | -------------------------------------------------------------------------------- /projects/random-password-generator/source.txt: -------------------------------------------------------------------------------- 1 | 0123456789abcdefghijklmnopqrstuvwxtz!@#$%^&*()_+?:{}[]ABCDEFGHIJKLMNOPQRSTUVWXYZ -------------------------------------------------------------------------------- /projects/random-password-generator/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | justify-content: center; 4 | height: 100vh; 5 | align-items: center; 6 | margin: 0; 7 | font-family: "Courier New", Courier, monospace; 8 | } 9 | 10 | .password-container { 11 | background-color: pink; 12 | width: 500px; 13 | padding: 20px; 14 | border-radius: 10px; 15 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 16 | margin: 10px; 17 | } 18 | 19 | .input-container { 20 | border: solid 2px black; 21 | padding: 10px; 22 | border-radius: 10px; 23 | display: flex; 24 | justify-content: space-between; 25 | align-items: center; 26 | } 27 | 28 | .input { 29 | border: none; 30 | background-color: transparent; 31 | outline: none; 32 | font-size: 24px; 33 | letter-spacing: 4px; 34 | } 35 | 36 | .input::placeholder { 37 | letter-spacing: 0px; 38 | } 39 | 40 | .fa-copy { 41 | cursor: pointer; 42 | opacity: 0.3; 43 | } 44 | 45 | .fa-copy:hover { 46 | opacity: 0.7; 47 | } 48 | 49 | .btn { 50 | background: black; 51 | color: white; 52 | border: none; 53 | padding: 10px 20px; 54 | border-radius: 5px; 55 | margin: 10px 0; 56 | font-size: 20px; 57 | cursor: pointer; 58 | } 59 | 60 | .btn:hover { 61 | background-color: green; 62 | } 63 | 64 | .btn:active { 65 | transform: scale(0.95); 66 | } 67 | 68 | .alert-container { 69 | position: fixed; 70 | width: 300px; 71 | height: 50px; 72 | background-color: lightgreen; 73 | right: 20px; 74 | bottom: 20px; 75 | border-radius: 10px; 76 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 77 | display: flex; 78 | justify-content: center; 79 | align-items: center; 80 | font-size: 20px; 81 | transition: 0.4s; 82 | } 83 | 84 | .active.alert-container { 85 | right: -300px; 86 | } 87 | -------------------------------------------------------------------------------- /projects/random-photos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Random Photos 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/random-photos/index.js: -------------------------------------------------------------------------------- 1 | const imageContainerEl = document.querySelector(".image-container"); 2 | 3 | const btnEl = document.querySelector(".btn"); 4 | 5 | btnEl.addEventListener("click", () => { 6 | imageNum = 10; 7 | addNewImages(); 8 | }); 9 | 10 | function addNewImages() { 11 | for (let index = 0; index < imageNum; index++) { 12 | const newImgEl = document.createElement("img"); 13 | newImgEl.src = `https://picsum.photos/300?random=${Math.floor( 14 | Math.random() * 2000 15 | )}`; 16 | imageContainerEl.appendChild(newImgEl); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /projects/random-photos/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | background-color: brown; 7 | } 8 | 9 | .image-container { 10 | text-align: center; 11 | } 12 | 13 | .image-container img { 14 | margin: 10px; 15 | border-radius: 10px; 16 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 17 | background-color: lightgray; 18 | width: 300px; 19 | height: 300px; 20 | } 21 | 22 | .btn { 23 | background-color: slateblue; 24 | border: none; 25 | padding: 10px 20px; 26 | margin: 20px; 27 | color: white; 28 | border-radius: 5px; 29 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 30 | cursor: pointer; 31 | } 32 | 33 | .btn:hover { 34 | opacity: 0.9; 35 | } 36 | -------------------------------------------------------------------------------- /projects/random-quote-generator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Random Quote Generator 8 | 9 | 10 | 11 | 12 |
13 |

Random Quote Generator

14 |

15 | 16 | Quote 17 | 18 | 19 |

20 |

~ Author

21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/random-quote-generator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("btn"); 2 | const quoteEl = document.getElementById("quote"); 3 | const authorEl = document.getElementById("author"); 4 | 5 | const apiURL = "https://api.quotable.io/random"; 6 | 7 | async function getQuote() { 8 | try { 9 | btnEl.innerText = "Loading..."; 10 | btnEl.disabled = true; 11 | quoteEl.innerText = "Updating..."; 12 | authorEl.innerText = "Updating..."; 13 | const response = await fetch(apiURL); 14 | const data = await response.json(); 15 | const quoteContent = data.content; 16 | const quoteAuthor = data.author; 17 | quoteEl.innerText = quoteContent; 18 | authorEl.innerText = "~ " + quoteAuthor; 19 | btnEl.innerText = "Get a quote"; 20 | btnEl.disabled = false; 21 | console.log(data); 22 | } catch (error) { 23 | console.log(error); 24 | quoteEl.innerText = "An error happened, try again later"; 25 | authorEl.innerText = "An error happened"; 26 | btnEl.innerText = "Get a quote"; 27 | btnEl.disabled = false; 28 | } 29 | } 30 | 31 | getQuote() 32 | 33 | btnEl.addEventListener("click", getQuote); 34 | -------------------------------------------------------------------------------- /projects/random-quote-generator/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | min-height: 100vh; 5 | justify-content: center; 6 | align-items: center; 7 | font-family: "Courier New", Courier, monospace; 8 | background: linear-gradient(to left bottom, lightgreen, lightblue); 9 | } 10 | 11 | .container { 12 | background-color: rgba(255, 255, 255, 0.1); 13 | box-shadow: 0 6px 10px rgba(0, 0, 0, 0.3); 14 | padding: 30px; 15 | border-radius: 15px; 16 | width: 90%; 17 | margin: 10px; 18 | text-align: center; 19 | } 20 | 21 | .heading { 22 | font-size: 35px; 23 | font-weight: 700; 24 | } 25 | 26 | .quote { 27 | font-size: 30px; 28 | font-weight: 600; 29 | } 30 | 31 | .author { 32 | font-size: 25px; 33 | margin: 10px; 34 | font-style: italic; 35 | } 36 | 37 | .btn { 38 | font-size: 18px; 39 | border-radius: 5px; 40 | cursor: pointer; 41 | padding: 10px; 42 | margin-top: 15px; 43 | background-color: rgba(255, 255, 255, 0.3); 44 | border-color: rgba(255, 255, 255, 0.6); 45 | text-transform: uppercase; 46 | width: 300px; 47 | } 48 | 49 | .btn:hover{ 50 | background-color: rgba(255,255,255,.6); 51 | box-shadow: 0 4px 4px rgba(0,0,0,.3); 52 | transition: all 300ms ease-in-out; 53 | color: green; 54 | } 55 | -------------------------------------------------------------------------------- /projects/real-time-character-counter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Real-time Charater Counter 8 | 9 | 10 | 11 |
12 |

Real-time Charater Counter

13 | 19 |
20 |

21 | Total Charaters: 22 | 23 |

24 |

25 | Remaining: 26 | 27 |

28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /projects/real-time-character-counter/index.js: -------------------------------------------------------------------------------- 1 | const textareaEl = document.getElementById("textarea"); 2 | const totalCounterEl = document.getElementById("total-counter"); 3 | const remainingCounterEl = document.getElementById("remaining-counter"); 4 | 5 | textareaEl.addEventListener("keyup", () => { 6 | updateCounter(); 7 | }); 8 | 9 | updateCounter() 10 | 11 | function updateCounter() { 12 | totalCounterEl.innerText = textareaEl.value.length; 13 | remainingCounterEl.innerText = 14 | textareaEl.getAttribute("maxLength") - textareaEl.value.length; 15 | } 16 | -------------------------------------------------------------------------------- /projects/real-time-character-counter/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: salmon; 8 | font-family: cursive; 9 | } 10 | 11 | .container { 12 | background-color: lightpink; 13 | width: 400px; 14 | padding: 20px; 15 | margin: 5px; 16 | border-radius: 10px; 17 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 18 | } 19 | 20 | .textarea { 21 | resize: none; 22 | width: 100%; 23 | height: 100px; 24 | font-size: 18px; 25 | font-family: sans-serif; 26 | padding: 10px; 27 | box-sizing: border-box; 28 | border: solid 2px darkgray; 29 | } 30 | 31 | .counter-container { 32 | display: flex; 33 | justify-content: space-between; 34 | padding: 0 5px; 35 | } 36 | 37 | .counter-container p { 38 | font-size: 18px; 39 | color: gray; 40 | } 41 | 42 | .total-counter { 43 | color: slateblue; 44 | } 45 | 46 | .remaining-counter { 47 | color: orangered; 48 | } 49 | -------------------------------------------------------------------------------- /projects/recipe-book-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 |

Recipe Book App

13 |
14 | 15 |
16 | 54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /projects/recipe-book-app/index.js: -------------------------------------------------------------------------------- 1 | const API_KEY = "275d58779ccf4e22af03e792e8819fff"; 2 | const recipeListEl = document.getElementById("recipe-list"); 3 | 4 | function displayRecipes(recipes) { 5 | recipeListEl.innerHTML = ""; 6 | recipes.forEach((recipe) => { 7 | const recipeItemEl = document.createElement("li"); 8 | recipeItemEl.classList.add("recipe-item"); 9 | recipeImageEl = document.createElement("img"); 10 | recipeImageEl.src = recipe.image; 11 | recipeImageEl.alt = "recipe image"; 12 | 13 | recipeTitleEl = document.createElement("h2"); 14 | recipeTitleEl.innerText = recipe.title; 15 | 16 | recipeIngredientsEl = document.createElement("p"); 17 | recipeIngredientsEl.innerHTML = ` 18 | Ingredients: ${recipe.extendedIngredients 19 | .map((ingredient) => ingredient.original) 20 | .join(", ")} 21 | `; 22 | 23 | recipeLinkEl = document.createElement("a"); 24 | recipeLinkEl.href = recipe.sourceUrl; 25 | recipeLinkEl.innerText = "View Recipe"; 26 | 27 | recipeItemEl.appendChild(recipeImageEl); 28 | recipeItemEl.appendChild(recipeTitleEl); 29 | recipeItemEl.appendChild(recipeIngredientsEl); 30 | recipeItemEl.appendChild(recipeLinkEl); 31 | recipeListEl.appendChild(recipeItemEl); 32 | }); 33 | } 34 | 35 | async function getRecipes() { 36 | const response = await fetch( 37 | `https://api.spoonacular.com/recipes/random?number=10&apiKey=${API_KEY}` 38 | ); 39 | 40 | const data = await response.json(); 41 | 42 | return data.recipes; 43 | } 44 | 45 | async function init() { 46 | const recipes = await getRecipes(); 47 | displayRecipes(recipes); 48 | } 49 | 50 | init(); 51 | -------------------------------------------------------------------------------- /projects/recipe-book-app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: Arial, sans-serif; 5 | } 6 | 7 | header { 8 | background: #0c2461; 9 | color: #fff; 10 | padding: 20px; 11 | text-align: center; 12 | } 13 | 14 | h1 { 15 | margin: 0; 16 | font-size: 36px; 17 | } 18 | 19 | .container { 20 | margin: 0 auto; 21 | max-width: 1200px; 22 | padding: 20px; 23 | } 24 | 25 | .recipe-list { 26 | list-style: none; 27 | margin: 0; 28 | padding: 0; 29 | } 30 | 31 | .recipe-item { 32 | display: flex; 33 | align-items: center; 34 | justify-content: space-between; 35 | margin-bottom: 20px; 36 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); 37 | border-radius: 5px; 38 | overflow: hidden; 39 | } 40 | 41 | .recipe-item img { 42 | width: 150px; 43 | height: 150px; 44 | object-fit: cover; 45 | } 46 | 47 | .recipe-item h2 { 48 | margin: 0; 49 | font-size: 20px; 50 | padding: 10px; 51 | min-width: 200px; 52 | } 53 | 54 | .recipe-item p { 55 | margin: 0; 56 | padding: 10px; 57 | color: #777; 58 | } 59 | 60 | .recipe-item a { 61 | background: #0c2461; 62 | color: #fff; 63 | min-width: 150px; 64 | padding: 10px; 65 | text-decoration: none; 66 | text-transform: uppercase; 67 | font-size: 14px; 68 | transition: background 0.3s ease; 69 | } 70 | 71 | .recipe-item a:hover { 72 | background: #1e3799; 73 | } 74 | 75 | @media screen and (max-width: 768px) { 76 | .container { 77 | max-width: 90%; 78 | } 79 | .recipe-item { 80 | flex-direction: column; 81 | } 82 | 83 | .recipe-item img { 84 | width: 100%; 85 | height: auto; 86 | margin-bottom: 10px; 87 | } 88 | 89 | .recipe-item h2 { 90 | font-size: 20px; 91 | padding: 0; 92 | margin-bottom: 10px; 93 | } 94 | 95 | .recipe-item p { 96 | font-size: 14px; 97 | margin-bottom: 10px; 98 | } 99 | 100 | .recipe-item a { 101 | width: 100%; 102 | text-align: center; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /projects/rock-paper-scissors-game/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Rock Paper Scissors Game 8 | 9 | 10 | 11 |

Rock Paper Scissors Game

12 |

Choose your move:

13 |
14 | 15 | 16 | 17 |
18 |

19 |

20 | Your score: 0 21 | Computer score: 0 22 |

23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/rock-paper-scissors-game/index.js: -------------------------------------------------------------------------------- 1 | const buttons = document.querySelectorAll("button"); 2 | 3 | const resultEl = document.getElementById("result"); 4 | 5 | const playerScoreEl = document.getElementById("user-score"); 6 | 7 | const computerScoreEl = document.getElementById("computer-score"); 8 | 9 | let playerScore = 0; 10 | let computerScore = 0; 11 | 12 | buttons.forEach((button) => { 13 | button.addEventListener("click", () => { 14 | const result = playRound(button.id, computerPlay()); 15 | resultEl.textContent = result; 16 | 17 | }); 18 | }); 19 | 20 | function computerPlay() { 21 | const choices = ["rock", "paper", "scissors"]; 22 | const randomChoice = Math.floor(Math.random() * choices.length); 23 | return choices[randomChoice]; 24 | } 25 | 26 | function playRound(playerSelection, computerSelection) { 27 | if (playerSelection === computerSelection) { 28 | return "It's a tie!"; 29 | } else if ( 30 | (playerSelection === "rock" && computerSelection === "scissors") || 31 | (playerSelection === "paper" && computerSelection === "rock") || 32 | (playerSelection === "scissors" && computerSelection === "paper") 33 | ) { 34 | playerScore++; 35 | playerScoreEl.textContent = playerScore; 36 | return "You win! " + playerSelection + " beats " + computerSelection; 37 | } else { 38 | computerScore++; 39 | computerScoreEl.textContent = computerScore; 40 | return "You lose! " + computerSelection + " beats " + playerSelection; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /projects/rock-paper-scissors-game/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f1f1f1; 3 | font-family: "Arial", sans-serif; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | h1 { 9 | font-size: 2rem; 10 | text-align: center; 11 | padding-top: 100px; 12 | } 13 | 14 | p { 15 | font-size: 1.5rem; 16 | font-weight: 600; 17 | text-align: center; 18 | margin-bottom: 0.5rem; 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | justify-content: center; 24 | } 25 | 26 | button { 27 | border: none; 28 | font-size: 3rem; 29 | margin: 0 0.5rem; 30 | padding: 0.5rem; 31 | cursor: pointer; 32 | border-radius: 5px; 33 | transition: all 0.3s ease-in-out; 34 | } 35 | 36 | button:hover { 37 | opacity: 0.7; 38 | } 39 | 40 | #rock { 41 | background-color: #ff0000; 42 | } 43 | 44 | #paper { 45 | background-color: #2196f3; 46 | } 47 | 48 | #scissors { 49 | background-color: #4caf50; 50 | } 51 | 52 | #user-score { 53 | color: #2196f3; 54 | } 55 | 56 | #computer-score { 57 | color: #ff0000; 58 | } 59 | -------------------------------------------------------------------------------- /projects/rotating-image-gallery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Rotating Image Gallery 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /projects/rotating-image-gallery/index.js: -------------------------------------------------------------------------------- 1 | const imageContainerEl = document.querySelector(".image-container"); 2 | 3 | const prevEl = document.getElementById("prev"); 4 | const nextEl = document.getElementById("next"); 5 | let x = 0; 6 | let timer; 7 | prevEl.addEventListener("click", () => { 8 | x = x + 45; 9 | clearTimeout(timer); 10 | updateGallery(); 11 | }); 12 | nextEl.addEventListener("click", () => { 13 | x = x - 45; 14 | clearTimeout(timer); 15 | updateGallery(); 16 | }); 17 | 18 | function updateGallery() { 19 | imageContainerEl.style.transform = `perspective(1000px) rotateY(${x}deg)`; 20 | timer = setTimeout(() => { 21 | x = x - 45; 22 | updateGallery(); 23 | }, 3000); 24 | } 25 | 26 | updateGallery(); 27 | -------------------------------------------------------------------------------- /projects/rotating-image-gallery/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | text-align: center; 7 | height: 100vh; 8 | justify-content: center; 9 | background-color: black; 10 | overflow: hidden; 11 | } 12 | 13 | .image-container { 14 | position: relative; 15 | width: 200px; 16 | height: 200px; 17 | transform-style: preserve-3d; 18 | transform: perspective(1000px) rotateY(0deg); 19 | transition: transform 0.7s; 20 | } 21 | 22 | .image-container span { 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | width: 100%; 27 | transform: rotateY(calc(var(--i) * 45deg)) translateZ(400px); 28 | } 29 | 30 | .image-container span img { 31 | position: absolute; 32 | left: 0; 33 | top: 0; 34 | width: 100%; 35 | } 36 | 37 | .btn-container { 38 | position: relative; 39 | width: 80%; 40 | } 41 | 42 | .btn { 43 | position: absolute; 44 | bottom: -80px; 45 | background-color: slateblue; 46 | color: white; 47 | border: none; 48 | padding: 10px 20px; 49 | border-radius: 5px; 50 | cursor: pointer; 51 | } 52 | 53 | .btn:hover { 54 | filter: brightness(1.5); 55 | } 56 | 57 | #prev { 58 | left: 20%; 59 | } 60 | 61 | #next { 62 | right: 20%; 63 | } 64 | -------------------------------------------------------------------------------- /projects/sidebar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Sahand Ghavidel 8 | 9 | 10 | 11 | 12 | 13 | 14 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /projects/sidebar/index.js: -------------------------------------------------------------------------------- 1 | const bars = document.querySelector(".fa-bars"); 2 | const sidebar = document.querySelector(".sidebar"); 3 | const closingButton = document.querySelector(".fa-times"); 4 | 5 | bars.addEventListener("click", () => { 6 | sidebar.classList.toggle("show-sidebar"); 7 | }); 8 | 9 | closingButton.addEventListener("click", () => { 10 | sidebar.classList.remove("show-sidebar"); 11 | }); 12 | -------------------------------------------------------------------------------- /projects/sidebar/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | body { 7 | font-family: sans-serif; 8 | background: #ebebeb; 9 | } 10 | 11 | .menu a { 12 | display: block; 13 | font-size: 1.5rem; 14 | padding: 1rem 1.5rem; 15 | color: grey; 16 | transition: all 0.3s linear; 17 | text-decoration: none; 18 | } 19 | 20 | .sidebar { 21 | position: fixed; 22 | top: 0; 23 | left: 0; 24 | background: white; 25 | width: 100%; 26 | height: 100%; 27 | transition: all 0.3s linear; 28 | transform: translate(-100%); 29 | } 30 | 31 | .show-sidebar { 32 | transform: translate(0); 33 | } 34 | 35 | .fa-bars { 36 | position: fixed; 37 | top: 2rem; 38 | right: 3rem; 39 | color: #e94949; 40 | font-size: 1.5rem; 41 | cursor: pointer; 42 | } 43 | 44 | .fa-bars:hover { 45 | color: black; 46 | } 47 | 48 | .fa-times { 49 | font-size: 1.5rem; 50 | color: #e94949; 51 | cursor: pointer; 52 | } 53 | 54 | .fa-times:hover { 55 | color: black; 56 | } 57 | 58 | .sidebar-header { 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | padding: 1rem 1.5rem; 63 | } 64 | 65 | .logo { 66 | margin-left: -15px; 67 | } 68 | 69 | @media (min-width: 676px) { 70 | .sidebar { 71 | width: 500px; 72 | } 73 | } 74 | 75 | .menu a:hover { 76 | background: #f8a5a5; 77 | padding-left: 1.7rem; 78 | } 79 | -------------------------------------------------------------------------------- /projects/social-media-selector-menu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Social Media Selector Menu 8 | 15 | 16 | 17 | 18 | 22 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /projects/social-media-selector-menu/index.js: -------------------------------------------------------------------------------- 1 | const menuEl = document.querySelector(".menu"); 2 | const menuTextEl = document.querySelector(".menu p"); 3 | const socialListsEl = document.querySelector(".social-lists"); 4 | const liEls = document.querySelectorAll(".social-lists li"); 5 | 6 | menuEl.addEventListener("click", () => { 7 | socialListsEl.classList.toggle("hide"); 8 | menuEl.classList.toggle("rotate"); 9 | }); 10 | 11 | liEls.forEach((liEl) => { 12 | liEl.addEventListener("click", () => { 13 | menuTextEl.innerHTML = liEl.innerHTML; 14 | socialListsEl.classList.add("hide"); 15 | menuEl.classList.toggle("rotate"); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /projects/social-media-selector-menu/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | height: 100vh; 7 | justify-content: center; 8 | font-family: sans-serif; 9 | background: linear-gradient(135deg, purple 20%, orange 80%); 10 | } 11 | 12 | .menu { 13 | background: lightgrey; 14 | width: 300px; 15 | opacity: 0.3; 16 | border-radius: 5px; 17 | display: flex; 18 | align-items: center; 19 | justify-content: space-between; 20 | padding: 10px; 21 | cursor: pointer; 22 | } 23 | 24 | .menu .fas{ 25 | transition: transform .2s; 26 | } 27 | 28 | .menu p { 29 | margin: 0 10px; 30 | display: flex; 31 | align-items: center; 32 | } 33 | 34 | .social-lists { 35 | background: lightgray; 36 | width: 300px; 37 | padding: 10px; 38 | opacity: 0.3; 39 | list-style-type: none; 40 | border-radius: 5px; 41 | } 42 | 43 | .social-lists li { 44 | display: flex; 45 | align-items: center; 46 | cursor: pointer; 47 | transition: padding 0.2s linear; 48 | } 49 | 50 | .social-lists li:hover { 51 | background: darkgray; 52 | border-radius: 5px; 53 | padding-left: 10px; 54 | } 55 | 56 | .social-lists li .fab { 57 | margin: 0 10px; 58 | } 59 | 60 | .rotate .fas { 61 | transform: rotate(180deg); 62 | } 63 | 64 | .hide { 65 | visibility: hidden; 66 | } 67 | -------------------------------------------------------------------------------- /projects/step-progress-bar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Step Progress Bar 8 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 | 24 | Start 25 |
26 |
27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | 42 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /projects/step-progress-bar/index.js: -------------------------------------------------------------------------------- 1 | const nextEl = document.getElementById("next"); 2 | const prevEl = document.getElementById("prev"); 3 | 4 | const progressEl = document.querySelector(".progress-bar-front"); 5 | 6 | const stepsEl = document.querySelectorAll(".step"); 7 | 8 | let currentChecked = 1; 9 | 10 | nextEl.addEventListener("click", () => { 11 | currentChecked++; 12 | if (currentChecked > stepsEl.length) { 13 | currentChecked = stepsEl.length; 14 | } 15 | updateStepProgress(); 16 | }); 17 | 18 | prevEl.addEventListener("click", () => { 19 | currentChecked--; 20 | if (currentChecked < 1) { 21 | currentChecked = 1; 22 | } 23 | updateStepProgress(); 24 | }); 25 | 26 | function updateStepProgress() { 27 | stepsEl.forEach((stepEl, idx) => { 28 | if (idx < currentChecked) { 29 | stepEl.classList.add("checked"); 30 | stepEl.innerHTML = ` 31 | 32 | ${ 33 | idx === 0 34 | ? "Start" 35 | : idx === stepsEl.length - 1 36 | ? "Final" 37 | : "Step " + idx 38 | } 39 | `; 40 | } else { 41 | stepEl.classList.remove("checked"); 42 | stepEl.innerHTML = ` 43 | 44 | `; 45 | } 46 | }); 47 | 48 | const checkedNumber = document.querySelectorAll(".checked"); 49 | 50 | progressEl.style.width = 51 | ((checkedNumber.length - 1) / (stepsEl.length - 1)) * 100 + "%"; 52 | 53 | if (currentChecked === 1) { 54 | prevEl.disabled = true; 55 | } else if (currentChecked === stepsEl.length) { 56 | nextEl.disabled = true; 57 | } else { 58 | prevEl.disabled = false; 59 | nextEl.disabled = false; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /projects/step-progress-bar/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | background-color: yellow; 8 | } 9 | 10 | .container { 11 | text-align: center; 12 | } 13 | 14 | .progress-container { 15 | width: 500px; 16 | display: flex; 17 | position: relative; 18 | justify-content: space-between; 19 | } 20 | 21 | .progress-bar-back { 22 | position: absolute; 23 | height: 4px; 24 | width: 100%; 25 | background-color: lightgray; 26 | border: none; 27 | z-index: -1; 28 | margin: 0; 29 | top: 50%; 30 | transform: translateY(-50%); 31 | } 32 | .progress-bar-front { 33 | position: absolute; 34 | height: 4px; 35 | width: 0%; 36 | background-color: green; 37 | border: none; 38 | z-index: -1; 39 | margin: 0; 40 | top: 50%; 41 | transform: translateY(-50%); 42 | transition: 0.4s linear width; 43 | } 44 | 45 | .step { 46 | width: 30px; 47 | height: 30px; 48 | background-color: white; 49 | border-radius: 50%; 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | border: 4px solid lightgray; 54 | color: lightgray; 55 | } 56 | 57 | .step.checked { 58 | color: green; 59 | border-color: green; 60 | transition: all 0.4s linear; 61 | transition-delay: 0.3s; 62 | } 63 | 64 | .step.checked small { 65 | position: absolute; 66 | bottom: -20px; 67 | font-family: cursive; 68 | } 69 | 70 | .btn { 71 | background-color: slateblue; 72 | border: none; 73 | color: white; 74 | padding: 10px 20px; 75 | margin: 70px 10px 0; 76 | border-radius: 5px; 77 | cursor: pointer; 78 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 79 | } 80 | 81 | .btn:hover { 82 | opacity: 0.9; 83 | } 84 | 85 | .btn:active { 86 | transform: scale(0.97); 87 | } 88 | 89 | .btn:disabled { 90 | background-color: lightgray; 91 | } 92 | 93 | @media (max-width: 500px) { 94 | .progress-container { 95 | width: 90vw; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /projects/sticky-navbar/index.js: -------------------------------------------------------------------------------- 1 | const navbarEl = document.querySelector(".navbar"); 2 | 3 | const bottomContainerEl = document.querySelector(".bottom-container"); 4 | 5 | console.log(navbarEl.offsetHeight); 6 | 7 | console.log(bottomContainerEl.offsetTop); 8 | 9 | window.addEventListener("scroll", () => { 10 | if ( 11 | window.scrollY > 12 | bottomContainerEl.offsetTop - navbarEl.offsetHeight - 50 13 | ) { 14 | navbarEl.classList.add("active"); 15 | } else { 16 | navbarEl.classList.remove("active"); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /projects/sticky-navbar/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .top-container { 6 | background-image: url("https://images.unsplash.com/photo-1547394765-185e1e68f34e?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1170&q=80"); 7 | height: 100vh; 8 | background-size: cover; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | text-align: center; 13 | } 14 | 15 | .top-container h1 { 16 | color: white; 17 | font-size: 50px; 18 | font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif; 19 | letter-spacing: 2px; 20 | } 21 | 22 | .text { 23 | margin: 50px 5%; 24 | font-family: sans-serif; 25 | } 26 | 27 | .navbar { 28 | display: flex; 29 | position: fixed; 30 | background-color: white; 31 | width: 100%; 32 | justify-content: space-between; 33 | align-items: center; 34 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 35 | transition: background-color 0.4s; 36 | } 37 | 38 | .navbar ul { 39 | display: flex; 40 | list-style-type: none; 41 | } 42 | 43 | .navbar ul li a { 44 | text-decoration: none; 45 | margin: 0 10px; 46 | color: black; 47 | font-family: cursive; 48 | } 49 | 50 | .navbar ul li a:hover { 51 | color: red; 52 | } 53 | 54 | .navbar.active { 55 | background-color: black; 56 | } 57 | 58 | .navbar.active ul li a { 59 | color: white; 60 | } 61 | -------------------------------------------------------------------------------- /projects/stopwatch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stopwatch 8 | 9 | 10 | 11 | 12 |
00:00:00
13 |
14 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /projects/stopwatch/index.js: -------------------------------------------------------------------------------- 1 | const timerEl = document.getElementById("timer"); 2 | const startButtonEl = document.getElementById("start"); 3 | const stopButtonEl = document.getElementById("stop"); 4 | const resetButtonEl = document.getElementById("reset"); 5 | 6 | let startTime = 0; 7 | let elapsedTime = 0; 8 | let timerInterval; 9 | 10 | function startTimer() { 11 | startTime = Date.now() - elapsedTime; 12 | 13 | timerInterval = setInterval(() => { 14 | elapsedTime = Date.now() - startTime; 15 | timerEl.textContent = formatTime(elapsedTime); 16 | }, 10); 17 | 18 | startButtonEl.disabled = true; 19 | stopButtonEl.disabled = false; 20 | } 21 | 22 | function formatTime(elapsedTime) { 23 | const milliseconds = Math.floor((elapsedTime % 1000) / 10); 24 | const seconds = Math.floor((elapsedTime % (1000 * 60)) / 1000); 25 | const minutes = Math.floor((elapsedTime % (1000 * 60 * 60)) / (1000 * 60)); 26 | const hours = Math.floor(elapsedTime / (1000 * 60 * 60)); 27 | return ( 28 | (hours ? (hours > 9 ? hours : "0" + hours) : "00") + 29 | ":" + 30 | (minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") + 31 | ":" + 32 | (seconds ? (seconds > 9 ? seconds : "0" + seconds) : "00") + 33 | "." + 34 | (milliseconds > 9 ? milliseconds : "0" + milliseconds) 35 | ); 36 | } 37 | function stopTimer() { 38 | clearInterval(timerInterval); 39 | startButtonEl.disabled = false; 40 | stopButtonEl.disabled = true; 41 | } 42 | function resetTimer() { 43 | clearInterval(timerInterval); 44 | 45 | elapsedTime = 0; 46 | timerEl.textContent = "00:00:00"; 47 | 48 | startButtonEl.disabled = false; 49 | stopButtonEl.disabled = true; 50 | } 51 | 52 | startButtonEl.addEventListener("click", startTimer); 53 | stopButtonEl.addEventListener("click", stopTimer); 54 | resetButtonEl.addEventListener("click", resetTimer); 55 | -------------------------------------------------------------------------------- /projects/stopwatch/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f0f0f0; 3 | font-family: "Poppins", sans-serif; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | min-height: 100vh; 8 | overflow: hidden; 9 | align-items: center; 10 | } 11 | 12 | #timer { 13 | font-size: 7rem; 14 | font-weight: 700; 15 | text-shadow: 2px 2px #f8a5c2; 16 | color: #f92672; 17 | width: 600px; 18 | text-align: center; 19 | margin: 40px auto; 20 | } 21 | 22 | #buttons { 23 | display: flex; 24 | justify-content: center; 25 | } 26 | 27 | button { 28 | background-color: #f92672; 29 | color: white; 30 | border: none; 31 | font-size: 2rem; 32 | font-weight: bold; 33 | padding: 1.5rem 4rem; 34 | margin: 1rem; 35 | border-radius: 30px; 36 | cursor: pointer; 37 | box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.3); 38 | transition: all 0.2s; 39 | } 40 | 41 | button:hover { 42 | background-color: #f44583; 43 | box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.5); 44 | } 45 | 46 | button[disabled] { 47 | opacity: 0.5; 48 | cursor: default; 49 | } 50 | 51 | @media (max-width: 800px) { 52 | #timer { 53 | font-size: 4rem; 54 | width: 350px; 55 | } 56 | 57 | button { 58 | font-size: 1.5rem; 59 | padding: 1rem 2rem; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /projects/tabs/app.js: -------------------------------------------------------------------------------- 1 | const tabs = document.querySelector(".tabs"); 2 | const btns = document.querySelectorAll(".button"); 3 | const articles = document.querySelectorAll(".content"); 4 | tabs.addEventListener("click", function (e) { 5 | const id = e.target.dataset.id; 6 | if (id) { 7 | // remove selected from other buttons 8 | btns.forEach(function (btn) { 9 | btn.classList.remove("live"); 10 | }); 11 | e.target.classList.add("live"); 12 | // hide other articles 13 | articles.forEach(function (article) { 14 | article.classList.remove("live"); 15 | }); 16 | const element = document.getElementById(id); 17 | element.classList.add("live"); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /projects/tabs/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | background: #f5abc9; 6 | color: grey; 7 | } 8 | 9 | img { 10 | display: block; 11 | width: 100%; 12 | } 13 | 14 | .section-center { 15 | width: 90vw; 16 | margin: 0 auto; 17 | max-width: 1170px; 18 | min-width: 340px; 19 | padding: 5rem 0; 20 | } 21 | 22 | .image { 23 | margin-bottom: 2rem; 24 | } 25 | img { 26 | border-radius: 0.5rem; 27 | object-fit: cover; 28 | height: 30rem; 29 | } 30 | .tabs { 31 | background: #ffe5e2; 32 | border-radius: 0.5rem; 33 | grid-template-rows: auto 1fr; 34 | } 35 | .btn-container { 36 | display: grid; 37 | grid-template-columns: 1fr 1fr 1fr; 38 | } 39 | .button:nth-child(1) { 40 | border-top-left-radius: 0.5rem; 41 | } 42 | .button:nth-child(3) { 43 | border-top-right-radius: 0.5rem; 44 | } 45 | .button { 46 | padding: 1rem 0; 47 | border: none; 48 | font-size: 1rem; 49 | background: #b6c9f0; 50 | cursor: pointer; 51 | transition: all 0.3s linear; 52 | letter-spacing: 0.25rem; 53 | } 54 | .button:hover:not(.live) { 55 | background: #e93b81; 56 | color: white; 57 | } 58 | .tabs-content { 59 | padding: 2rem 1.5rem; 60 | } 61 | /* hide content */ 62 | .content { 63 | display: none; 64 | } 65 | .button.live { 66 | background: #ffe5e2; 67 | } 68 | .content.live { 69 | display: block; 70 | } 71 | 72 | @media (min-width: 992px) { 73 | .image { 74 | margin-bottom: 0; 75 | } 76 | 77 | .section-center { 78 | display: grid; 79 | grid-template-columns: 1fr 1fr; 80 | column-gap: 2rem; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /projects/temperature-converter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Temperature Converter 8 | 9 | 10 | 11 |
12 |

Temperature Converter

13 |
14 | 15 | 23 |
24 |
25 | 26 | 34 |
35 |
36 | 37 | 45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /projects/temperature-converter/index.js: -------------------------------------------------------------------------------- 1 | const celsiusEl = document.getElementById("celsius"); 2 | const fahrenheitEl = document.getElementById("fahrenheit"); 3 | const kelvinEl = document.getElementById("kelvin"); 4 | 5 | function computeTemp(event) { 6 | const currentValue = +event.target.value; 7 | 8 | switch (event.target.name) { 9 | case "celsius": 10 | kelvinEl.value = (currentValue + 273.32).toFixed(2); 11 | fahrenheitEl.value = (currentValue * 1.8 + 32).toFixed(2); 12 | break; 13 | case "fahrenheit": 14 | celsiusEl.value = ((currentValue - 32) / 1.8).toFixed(2); 15 | kelvinEl.value = ((currentValue - 32) / 1.8 + 273.32).toFixed(2); 16 | break; 17 | case "kelvin": 18 | celsiusEl.value = (currentValue - 273.32).toFixed(2); 19 | fahrenheitEl.value = ((currentValue - 273.32) * 1.8 + 32).toFixed(2); 20 | break; 21 | default: 22 | break; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /projects/temperature-converter/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: linear-gradient(to left bottom, lightgreen, lightblue); 4 | min-height: 100vh; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: monospace; 9 | color: darkcyan; 10 | } 11 | 12 | .container { 13 | background: rgba(255, 255, 255, 0.3); 14 | padding: 20px; 15 | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3); 16 | border-radius: 10px; 17 | width: 85%; 18 | max-width: 450px; 19 | min-width: 350px; 20 | display: flex; 21 | flex-direction: column; 22 | align-items: center; 23 | } 24 | 25 | .heading { 26 | font-size: 32px; 27 | } 28 | 29 | .temp-container { 30 | width: 100%; 31 | padding: 15px; 32 | font-weight: bold; 33 | font-size: 18px; 34 | } 35 | 36 | .input { 37 | width: 220px; 38 | font-family: monospace; 39 | padding: 5px; 40 | float: right; 41 | outline: none; 42 | background: rgba(255, 255, 255, 0.3); 43 | border-color: rgba(255, 255, 255, 0.5); 44 | color: darkgreen; 45 | font-size: 18px; 46 | } 47 | 48 | 49 | .input::placeholder{ 50 | color: darkgray; 51 | } 52 | -------------------------------------------------------------------------------- /projects/testimonial-slider/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Testimonial Slider 8 | 9 | 10 | 11 |
12 | user-image 16 |

17 | This is simply unbelievable! I would be lost without Apple. The very 18 | best. Not able to tell you how happy I am with Apple. 19 |

20 |

Cherise G

21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/testimonial-slider/index.js: -------------------------------------------------------------------------------- 1 | const testimonials = [ 2 | { 3 | name: "Cherise G", 4 | photoUrl: 5 | "https://images.unsplash.com/photo-1570295999919-56ceb5ecca61?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=880&q=80", 6 | text: "This is simply unbelievable! I would be lost without Apple. The very best. Not able to tell you how happy I am with Apple.", 7 | }, 8 | { 9 | name: "Rosetta Q", 10 | photoUrl: 11 | "https://images.unsplash.com/photo-1633332755192-727a05c4013d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=880&q=80", 12 | text: "I would also like to say thank you to all your staff. Wow what great service, I love it! Apple impressed me on multiple levels.", 13 | }, 14 | { 15 | name: "Constantine V", 16 | photoUrl: 17 | "https://images.unsplash.com/photo-1628157588553-5eeea00af15c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=880&q=80", 18 | text: "Thank you for making it painless, pleasant and most of all hassle free! I wish I would have thought of it first. The very best.", 19 | }, 20 | ]; 21 | 22 | const imgEl = document.querySelector("img"); 23 | const textEl = document.querySelector(".text"); 24 | const usernameEl = document.querySelector(".username"); 25 | 26 | let idx = 0; 27 | 28 | updateTestimonial(); 29 | 30 | function updateTestimonial() { 31 | const { name, photoUrl, text } = testimonials[idx]; 32 | imgEl.src = photoUrl; 33 | textEl.innerText = text; 34 | usernameEl.innerText = name; 35 | idx++; 36 | if (idx === testimonials.length) { 37 | idx = 0; 38 | } 39 | setTimeout(() => { 40 | updateTestimonial(); 41 | }, 10000); 42 | } 43 | -------------------------------------------------------------------------------- /projects/testimonial-slider/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | height: 100vh; 6 | align-items: center; 7 | font-family: cursive; 8 | } 9 | 10 | .testimonial-container { 11 | width: 500px; 12 | height: 100px; 13 | background-color: slateblue; 14 | border-radius: 10px; 15 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); 16 | min-width: 400px; 17 | padding: 70px 20px; 18 | margin: 5px; 19 | color: white; 20 | position: relative; 21 | } 22 | 23 | img { 24 | width: 100px; 25 | height: 100px; 26 | border-radius: 50%; 27 | position: absolute; 28 | left: 50%; 29 | transform: translateX(-50%); 30 | top: -50px; 31 | } 32 | 33 | .username { 34 | font-size: 13px; 35 | font-weight: 100; 36 | } 37 | -------------------------------------------------------------------------------- /projects/tip-calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tip Calculator 8 | 9 | 10 | 11 |
12 |

Tip Calculator

13 |

Enter the bill amount and tip percentage to calculate the total.

14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /projects/tip-calculator/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.getElementById("calculate"); 2 | const billInput = document.getElementById("bill"); 3 | const tipInput = document.getElementById("tip"); 4 | const totalSpan = document.getElementById("total"); 5 | 6 | function calculateTotal() { 7 | const billValue = billInput.value; 8 | const tipValue = tipInput.value; 9 | const totalValue = billValue * (1 + tipValue / 100); 10 | totalSpan.innerText = totalValue.toFixed(2); 11 | } 12 | 13 | btnEl.addEventListener("click", calculateTotal); 14 | -------------------------------------------------------------------------------- /projects/tip-calculator/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: #f2f2f2; 7 | font-family: "Helvetica", sans-serif; 8 | } 9 | 10 | .container { 11 | background-color: white; 12 | max-width: 600px; 13 | margin: 100px auto; 14 | padding: 20px; 15 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); 16 | border-radius: 10px; 17 | } 18 | 19 | h1 { 20 | margin-top: 0; 21 | text-align: center; 22 | } 23 | 24 | input { 25 | padding: 10px; 26 | border: 1px solid #ccc; 27 | border-radius: 4px; 28 | margin: 10px 0; 29 | width: 100%; 30 | } 31 | 32 | button { 33 | background-color: #4caf50; 34 | color: white; 35 | padding: 10px; 36 | border: none; 37 | cursor: pointer; 38 | margin: 10px 0; 39 | width: 100%; 40 | font-size: 18px; 41 | text-transform: uppercase; 42 | transition: background-color 0.2s ease; 43 | } 44 | 45 | button:hover { 46 | background-color: #45a049; 47 | } 48 | 49 | #total { 50 | font-size: 24px; 51 | font-weight: bold; 52 | margin-top: 10px; 53 | } 54 | -------------------------------------------------------------------------------- /projects/to-do-list/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | To Do List 8 | 15 | 16 | 17 | 18 |
19 | 25 | 35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /projects/to-do-list/index.js: -------------------------------------------------------------------------------- 1 | const formEl = document.querySelector(".form"); 2 | 3 | const inputEl = document.querySelector(".input"); 4 | 5 | const ulEl = document.querySelector(".list"); 6 | 7 | let list = JSON.parse(localStorage.getItem("list")); 8 | if (list) { 9 | list.forEach((task) => { 10 | toDoList(task); 11 | }); 12 | } 13 | 14 | formEl.addEventListener("submit", (event) => { 15 | event.preventDefault(); 16 | toDoList(); 17 | }); 18 | 19 | function toDoList(task) { 20 | let newTask = inputEl.value; 21 | if (task) { 22 | newTask = task.name; 23 | } 24 | 25 | const liEl = document.createElement("li"); 26 | if (task && task.checked) { 27 | liEl.classList.add("checked"); 28 | } 29 | liEl.innerText = newTask; 30 | ulEl.appendChild(liEl); 31 | inputEl.value = ""; 32 | const checkBtnEl = document.createElement("div"); 33 | checkBtnEl.innerHTML = ` 34 | 35 | `; 36 | liEl.appendChild(checkBtnEl); 37 | const trashBtnEl = document.createElement("div"); 38 | trashBtnEl.innerHTML = ` 39 | 40 | `; 41 | liEl.appendChild(trashBtnEl); 42 | 43 | checkBtnEl.addEventListener("click", () => { 44 | liEl.classList.toggle("checked"); 45 | updateLocalStorage(); 46 | }); 47 | 48 | trashBtnEl.addEventListener("click", () => { 49 | liEl.remove(); 50 | updateLocalStorage(); 51 | }); 52 | updateLocalStorage(); 53 | } 54 | 55 | function updateLocalStorage() { 56 | const liEls = document.querySelectorAll("li"); 57 | list = []; 58 | liEls.forEach((liEl) => { 59 | list.push({ 60 | name: liEl.innerText, 61 | checked: liEl.classList.contains("checked"), 62 | }); 63 | }); 64 | localStorage.setItem("list", JSON.stringify(list)); 65 | } 66 | -------------------------------------------------------------------------------- /projects/to-do-list/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | display: flex; 4 | justify-content: center; 5 | background-color: greenyellow; 6 | } 7 | 8 | .form{ 9 | position: absolute; 10 | top: 30%; 11 | box-shadow: 0 4px 8px rgba(0,0,0,.3); 12 | width: 400px; 13 | background-color:yellow; 14 | border-radius: 10px; 15 | } 16 | 17 | .input{ 18 | width: 100%; 19 | box-sizing: border-box; 20 | padding: 20px; 21 | border-radius: 10px 10px 0 0; 22 | border: none; 23 | font-size: 20px; 24 | font-family: cursive; 25 | } 26 | 27 | .input::placeholder{ 28 | color: lightgray; 29 | } 30 | 31 | .list{ 32 | padding: 0; 33 | margin: 0; 34 | } 35 | 36 | .list li{ 37 | list-style-type: none; 38 | padding: 20px; 39 | font-family: cursive; 40 | border-top: dotted; 41 | border-color: darkgray; 42 | position: relative; 43 | } 44 | 45 | .list li .fa-trash{ 46 | color: red; 47 | position: absolute; 48 | right: 20px; 49 | top: 50%; 50 | transform: translateY(-50%); 51 | cursor: pointer; 52 | } 53 | .list li .fa-check-square{ 54 | color: green; 55 | position: absolute; 56 | right: 40px; 57 | top: 50%; 58 | transform: translateY(-50%); 59 | cursor: pointer; 60 | } 61 | 62 | .list li.checked { 63 | color: darkgray; 64 | text-decoration: line-through; 65 | } 66 | 67 | .list li.checked .fa-check-square{ 68 | color: darkgray; 69 | } -------------------------------------------------------------------------------- /projects/video-trailer-popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Video Trailer Popup 8 | 15 | 16 | 17 | 18 |
19 | movie-image 23 |

Movie Title

24 |

25 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Illum iste 26 | necessitatibus porro explicabo illo dolorum dolores cupiditate non modi 27 | quasi nobis, earum ab, autem esse vero sapiente minus vel! Provident? 28 |

29 | 30 |
31 |
32 | 33 | 34 |
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /projects/video-trailer-popup/index.js: -------------------------------------------------------------------------------- 1 | const btnEl = document.querySelector(".btn"); 2 | const closeIconEl = document.querySelector(".close-icon"); 3 | const trailerContainerEl = document.querySelector(".trailer-container"); 4 | const videoEl = document.querySelector("video"); 5 | 6 | btnEl.addEventListener("click", () => { 7 | trailerContainerEl.classList.remove("active"); 8 | }); 9 | 10 | closeIconEl.addEventListener("click", () => { 11 | trailerContainerEl.classList.add("active"); 12 | videoEl.pause(); 13 | videoEl.currentTime = 0; 14 | }); 15 | -------------------------------------------------------------------------------- /projects/video-trailer-popup/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | box-sizing: border-box; 4 | font-family: sans-serif; 5 | display: flex; 6 | justify-content: center; 7 | height: 100vh; 8 | align-items: center; 9 | background-color: black; 10 | } 11 | 12 | .main-container { 13 | max-width: 550px; 14 | padding: 10px; 15 | } 16 | 17 | .main-container img { 18 | max-width: 100%; 19 | margin-bottom: 15px; 20 | border-radius: 10px; 21 | } 22 | 23 | .main-container h1 { 24 | color: white; 25 | font-weight: 500; 26 | } 27 | 28 | .main-container p { 29 | color: white; 30 | margin: 15px 0; 31 | } 32 | 33 | .btn { 34 | background-color: white; 35 | border: none; 36 | padding: 10px 20px; 37 | cursor: pointer; 38 | border-radius: 5px; 39 | } 40 | 41 | .btn:hover { 42 | background-color: orange; 43 | } 44 | 45 | .trailer-container { 46 | position: fixed; 47 | top: 50%; 48 | left: 50%; 49 | transform: translate(-50%, -50%); 50 | background-color: black; 51 | width: 100%; 52 | height: 100%; 53 | display: flex; 54 | justify-content: center; 55 | align-items: center; 56 | opacity: 1; 57 | transition: opacity 0.7s; 58 | } 59 | 60 | .active.trailer-container { 61 | visibility: hidden; 62 | opacity: 0; 63 | } 64 | 65 | .trailer-container video { 66 | position: relative; 67 | max-width: 900px; 68 | outline: none; 69 | } 70 | 71 | @media (max-width: 991px) { 72 | .trailer-container video { 73 | max-width: 90%; 74 | } 75 | } 76 | 77 | .close-icon { 78 | position: absolute; 79 | top: 30px; 80 | right: 30px; 81 | color: white; 82 | cursor: pointer; 83 | } 84 | -------------------------------------------------------------------------------- /projects/video-trailer-popup/trailer.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sahandghavidel/HTML-CSS-JavaScript-projects-for-beginners/9178903cb14285736df153332c97209e8eab3ab1/projects/video-trailer-popup/trailer.mp4 -------------------------------------------------------------------------------- /projects/weather-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Weather App 8 | 9 | 10 | 11 |
12 |

Weather App

13 |
14 | 15 | 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 | 27 |
28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /projects/weather-app/index.js: -------------------------------------------------------------------------------- 1 | const apikey = "46f80a02ecae410460d59960ded6e1c6"; 2 | 3 | const weatherDataEl = document.getElementById("weather-data"); 4 | 5 | const cityInputEl = document.getElementById("city-input"); 6 | 7 | const formEl = document.querySelector("form"); 8 | 9 | formEl.addEventListener("submit", (event) => { 10 | event.preventDefault(); 11 | const cityValue = cityInputEl.value; 12 | getWeatherData(cityValue); 13 | }); 14 | 15 | async function getWeatherData(cityValue) { 16 | try { 17 | const response = await fetch( 18 | `https://api.openweathermap.org/data/2.5/weather?q=${cityValue}&appid=${apikey}&units=metric` 19 | ); 20 | 21 | if (!response.ok) { 22 | throw new Error("Network response was not ok"); 23 | } 24 | 25 | const data = await response.json(); 26 | 27 | const temperature = Math.round(data.main.temp); 28 | 29 | const description = data.weather[0].description; 30 | 31 | const icon = data.weather[0].icon; 32 | 33 | const details = [ 34 | `Feels like: ${Math.round(data.main.feels_like)}`, 35 | `Humidity: ${data.main.humidity}%`, 36 | `Wind speed: ${data.wind.speed} m/s`, 37 | ]; 38 | 39 | weatherDataEl.querySelector( 40 | ".icon" 41 | ).innerHTML = `Weather Icon`; 42 | weatherDataEl.querySelector( 43 | ".temperature" 44 | ).textContent = `${temperature}°C`; 45 | weatherDataEl.querySelector(".description").textContent = description; 46 | 47 | weatherDataEl.querySelector(".details").innerHTML = details 48 | .map((detail) => `
${detail}
`) 49 | .join(""); 50 | } catch (error) { 51 | weatherDataEl.querySelector(".icon").innerHTML = ""; 52 | weatherDataEl.querySelector(".temperature").textContent = ""; 53 | weatherDataEl.querySelector(".description").textContent = 54 | "An error happened, please try again later"; 55 | 56 | weatherDataEl.querySelector(".details").innerHTML = ""; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /projects/weather-app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: "Montserrat", sans-serif; 4 | background-color: #f7f7f7; 5 | } 6 | 7 | .container { 8 | background-color: #fff; 9 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); 10 | margin: 0 auto; 11 | margin-top: 50px; 12 | text-align: center; 13 | max-width: 600px; 14 | border-radius: 5px; 15 | padding: 20px; 16 | } 17 | 18 | form { 19 | display: flex; 20 | justify-content: center; 21 | align-items: center; 22 | margin-bottom: 20px; 23 | } 24 | 25 | form input[type="text"] { 26 | padding: 10px; 27 | border: none; 28 | outline: none; 29 | font-size: 18px; 30 | width: 60%; 31 | } 32 | 33 | form input[type="submit"] { 34 | background-color: #007bff; 35 | color: #fff; 36 | border: none; 37 | padding: 10px 20px; 38 | border-radius: 5px; 39 | font-size: 18px; 40 | cursor: pointer; 41 | outline: none; 42 | transition: background-color 0.3s ease; 43 | } 44 | 45 | form input[type="submit"]:hover { 46 | background-color: #0062cc; 47 | } 48 | 49 | .icon img { 50 | width: 100px; 51 | height: 100px; 52 | background-size: contain; 53 | background-repeat: no-repeat; 54 | background-position: center center; 55 | } 56 | 57 | .temperature { 58 | font-size: 48px; 59 | font-weight: bold; 60 | margin: 20px 0; 61 | } 62 | 63 | .description{ 64 | font-size: 24px; 65 | margin-bottom: 20px; 66 | } 67 | 68 | .details{ 69 | display: flex; 70 | justify-content: center; 71 | align-items: center; 72 | flex-wrap: wrap; 73 | } 74 | 75 | .details > div{ 76 | padding: 20px; 77 | background-color: #f1f1f1; 78 | margin: 10px; 79 | flex: 1; 80 | border-radius: 5px; 81 | text-align: center; 82 | min-height: 45px; 83 | } 84 | 85 | @media (max-width: 768px){ 86 | form { 87 | flex-direction: column; 88 | } 89 | 90 | form input[type="text"]{ 91 | width: 100%; 92 | margin-bottom: 10px; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /projects/weight-converter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Weight Converter 8 | 9 | 10 | 11 |
12 |

Weight Converter

13 |
14 | 15 | 16 |
17 |

Your weight in kg is:

18 |

19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /projects/weight-converter/index.js: -------------------------------------------------------------------------------- 1 | const inputEl = document.getElementById("input"); 2 | const errorEl = document.getElementById("error"); 3 | const resultEl = document.getElementById("result"); 4 | let errorTime; 5 | let resultTime; 6 | function updateResults() { 7 | if (inputEl.value <= 0 || isNaN(inputEl.value)) { 8 | errorEl.innerText = "Please enter a valid number!"; 9 | clearTimeout(errorTime); 10 | errorTime = setTimeout(() => { 11 | errorEl.innerText = ""; 12 | inputEl.value = ""; 13 | }, 2000); 14 | } else { 15 | resultEl.innerText = (+inputEl.value / 2.2).toFixed(2); 16 | clearTimeout(resultTime); 17 | resultTime = setTimeout(() => { 18 | resultEl.innerText = ""; 19 | inputEl.value = ""; 20 | }, 10000); 21 | } 22 | } 23 | 24 | inputEl.addEventListener("input", updateResults); 25 | -------------------------------------------------------------------------------- /projects/weight-converter/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0; 3 | background: linear-gradient(to left top, yellow, lightblue, yellow); 4 | min-height: 100vh; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | font-family: 'Courier New', Courier, monospace; 9 | color: darkcyan; 10 | } 11 | 12 | .container{ 13 | background: rgba(255,255,255,0.3); 14 | padding: 20px; 15 | box-shadow: 0 4px 10px rgba(0,0,0,.3); 16 | border-radius: 10px; 17 | width: 85%; 18 | max-width: 450px; 19 | } 20 | 21 | .input-container{ 22 | display: flex; 23 | justify-content: space-between; 24 | align-items: center; 25 | font-size: 18px; 26 | font-weight: 700; 27 | } 28 | 29 | .input{ 30 | padding: 10px; 31 | width: 70%; 32 | background: rgba(255,255,255,0.3); 33 | border-color: rgba(255,255,255,0.5); 34 | font-size: 18px; 35 | border-radius: 10px; 36 | color: darkgreen; 37 | outline: none; 38 | } 39 | 40 | .error{ 41 | color: red; 42 | } --------------------------------------------------------------------------------