├── 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 |
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 |
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 | Get Anime
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 |
17 |
18 |
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 |
15 |
16 |
17 |
18 | Sahand Ghavidel
19 |
20 |
21 |
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 | C
15 | /
16 | *
17 | -
18 | 7
19 | 8
20 | 9
21 | +
22 | 4
23 | 5
24 | 6
25 | =
26 | 1
27 | 2
28 | 3
29 | 0
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 | Click to join
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 | Compute BMI
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 |
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 | Reset
19 |
20 |
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 |
15 | AUD
16 | CAD
17 | EUR
18 | GBP
19 | INR
20 | JPY
21 | USD
22 |
23 |
24 |
25 |
26 |
27 | AUD
28 | CAD
29 | EUR
30 | GBP
31 | INR
32 | JPY
33 | USD
34 |
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 |
Tell me a joke
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 |
13 |
14 |
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 | Roll Dice
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 | Buy Now
15 |
16 |
17 |
Samsung
18 | Buy Now
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 |
Send Review
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 |
16 |
17 |
53 |
54 | Show more
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 |
21 |
22 |
23 |
24 |
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 |
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 |
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 |
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 |
18 |
19 |
23 |
34 |
35 |
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 |
Get Photos
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 |
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 | Start
16 | Stop
17 | Reset
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 |
Click
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 |
Generate
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 | Load More
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 |
Get a quote
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 |
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 | Prev
39 | Next
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 |
23 |
24 |
25 | Facebook
26 |
27 |
28 |
29 | YouTube
30 |
31 |
32 |
33 | Twitter
34 |
35 |
36 |
37 | Linkedin
38 |
39 |
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 |
40 |
41 |
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 | Start
15 | Stop
16 | Reset
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 |
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 |
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 |
Bill amount:
15 |
16 |
17 |
Tip percentage:
18 |
19 |
20 |
Calculate
21 |
22 |
Total:
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 |
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 |
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 |
Watch now
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 |
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 = ` `;
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 | Pounds:
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 | }
--------------------------------------------------------------------------------