├── color-picker
├── script.js
├── index.html
└── style.css
├── faq-accordion
├── index.html
├── style.css
└── script.js
├── weather-app
├── index.html
├── style.css
└── script.js
├── number-guessing-game
├── index.html
├── style.css
└── script.js
├── typing-speed-test
├── index.html
├── style.css
└── script.js
├── paint-app
├── index.html
├── style.css
└── script.js
├── todo-list
├── index.html
├── style.css
└── script.js
├── random-quote-generator
├── index.html
├── style.css
└── script.js
├── quiz-app
├── index.html
├── style.css
└── script.js
├── count-down-timer
├── index.html
├── style.css
└── script.js
├── calculator
├── style.css
├── index.html
└── script.js
├── carousel-image-slider
├── script.js
├── index.html
└── style.css
├── audio-app
├── index.html
├── style.css
└── script.js
└── shopping-cart
├── index.html
├── styles.css
└── main.js
/color-picker/script.js:
--------------------------------------------------------------------------------
1 | document.getElementById("colorInput").addEventListener("input", function(event){
2 | // Get the Selected color from input
3 | let selectedColor = event.target.value
4 |
5 | // Update the color text
6 | document.getElementById("colorCode").textContent = selectedColor
7 |
8 | // Update the background color of the display box
9 | document.getElementById("colorDisplay").style.backgroundColor = selectedColor
10 |
11 |
12 | })
--------------------------------------------------------------------------------
/faq-accordion/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | FAQ Accordion
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/color-picker/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Color Picker App
7 |
8 |
9 |
10 |
11 |
Color Picker
12 |
13 |
14 |
Selected Color: #ffffff
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/weather-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Weather App
7 |
8 |
9 |
10 |
11 |
Weather App
12 |
13 |
Your Location
14 |
Temperature: -- °C
15 |
Description: --
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/number-guessing-game/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Number Guessing Game
7 |
8 |
9 |
10 |
11 |
Number Guessing Game
12 |
Guess a number between 1 and 100 !
13 |
14 |
15 |
16 |
17 |
18 |
Good Luck! Start Guessing . . .
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/typing-speed-test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Typing Speed Test
7 |
8 |
9 |
10 |
11 |
Typing Speed Test
12 |
The quick brown fox jumps over the lazy dog.
13 |
15 |
16 |
17 |
Time : 0 seconds
18 |
Words per Minute: 0 WPM
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/weather-app/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: Arial, sans-serif;
3 | background-color: #87ceeb;
4 | margin: 0;
5 | padding: 0;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | height: 100vh;
10 | }
11 |
12 | .weather-container{
13 | background-color: #ffffff;
14 | padding: 30px;
15 | border-radius: 10px;
16 | box-shadow: 0 8px 20px rgba(0,0,0,0.1);
17 | width: 90%;
18 | max-width: 400px;
19 | text-align: center;
20 | }
21 |
22 | h1{
23 | font-size: 2.5em;
24 | color: #333;
25 | margin-bottom: 20px;
26 | }
27 | .weather-info{
28 | margin-bottom: 20px;
29 | }
30 | .weather-info h2{
31 | font-size: 1.8em;
32 | color: #555;
33 | }
34 | .weather-info p {
35 | font-size: 1.2em;
36 | color: #666;
37 | }
38 | .weather-icon {
39 | margin-top: 20px;
40 | }
41 | .weather-icon img {
42 | width: 100px;
43 | height: 100px;
44 | }
--------------------------------------------------------------------------------
/paint-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Simple Paint App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/paint-app/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: 'Arial', sans-serif;
3 | margin: 0;
4 | padding: 0;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | height: 100vh;
9 | background-color: #f0f0f0;
10 | }
11 |
12 | .paint-app{
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | background-color: #ffffff;
17 | border: 1px solid #cccccc;
18 | box-shadow: 0 4px 8px rgba(0,0,0,0.1);
19 | border-radius: 8px;
20 | padding: 10px;
21 | }
22 |
23 | .toolbar{
24 | display: flex;
25 | align-items: center;
26 | margin-bottom: 10px;
27 | gap: 10px;
28 | }
29 |
30 | .tool{
31 | background-color: #eeeeee;
32 | border: none;
33 | border-radius: 4px;
34 | padding: 8px;
35 | cursor: pointer;
36 | }
37 | .tool.active{
38 | background-color: #cccccc;
39 | }
40 |
41 | canvas{
42 | border: 1px solid #000000;
43 | border-radius: 4px;
44 | background-color: #fff;
45 | }
--------------------------------------------------------------------------------
/color-picker/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Arial', sans-serif;
3 | background-color: #f0f0f0;
4 | margin: 0;
5 | padding: 0;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | height: 100vh;
10 | }
11 | .container{
12 | text-align: center;
13 | background-color: #ffffff;
14 | padding: 30px;
15 | border-radius: 12px;
16 | box-shadow: 0 4px 10px rgba(0,0,0,0.1);
17 | max-width: 400px;
18 | width: 100%;
19 | }
20 | h1{
21 | font-size: 2em;
22 | color: #333333;
23 | margin-bottom: 20px;
24 |
25 | }
26 | .color-picker{
27 | margin-bottom: 20px;
28 | }
29 | #colorInput{
30 | width: 80px;
31 | height: 50px;
32 | border: none;
33 | cursor: pointer;
34 | }
35 | p{
36 | font-size: 1.2em;
37 | color: #555555;
38 | margin: 10px 0;
39 | }
40 | .color-display{
41 | width: 100%;
42 | height: 150px;
43 | border-radius: 12px;
44 | margin-top: 20px;
45 | transition: background-color 0.3s ease;
46 | }
--------------------------------------------------------------------------------
/todo-list/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | To-Do List
7 |
8 |
9 |
10 |
11 |
To-Do List App
12 |
13 |
14 |
17 |
18 |
19 |
20 |
Edit Modal
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/random-quote-generator/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Random Quote Generator
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Random Quote Generator
15 |
16 |
17 |
18 |
Click the button below to generate a random quote
19 |
20 |
- Author
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
--------------------------------------------------------------------------------
/quiz-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz App
7 |
8 |
9 |
10 |
11 |
Quiz App
12 |
13 |
14 |
Question text goes here
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
Your Score : 0 / 0
27 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/typing-speed-test/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: Arial, sans-serif;
3 | background-color: #f4f4f4;
4 | color: #333;
5 | text-align: center;
6 | margin: 0;
7 | padding: 0;
8 | }
9 | .container{
10 | max-width: 600px;
11 | margin: 100px auto;
12 | padding: 20px;
13 | background-color: #fff;
14 | border-radius: 8px;
15 | box-shadow: 0 0 10px rgba(0,0,0,0.1);
16 | }
17 |
18 | h1{
19 | margin-bottom: 20px;
20 | }
21 |
22 | #text-to-type{
23 | font-size: 18px;
24 | margin-bottom: 20px;
25 | line-height: 1.5;
26 | }
27 |
28 | #user-input{
29 | width: 100%;
30 | height: 100px;
31 | padding: 10px;
32 | font-size: 16px;
33 | border-radius: 4px;
34 | border: 1px solid #ccc;
35 | margin-bottom: 20px;
36 | }
37 |
38 | #start-button{
39 | padding: 10px 20px;
40 | font-size: 16px;
41 | color: #fff;
42 | background-color: #007bff;
43 | border: none;
44 | border-radius: 5px;
45 | cursor: pointer;
46 | }
47 | #results{
48 | margin-top: 20px;
49 | }
50 | #results p{
51 | font-size: 18px;
52 | margin: 5px 0;
53 | }
54 |
55 | #timer span, #wpm span{
56 | font-weight: bold;
57 | }
58 |
59 | .correct {
60 | color: green;
61 | }
62 |
63 | .incorrect{
64 | color: red;
65 | }
--------------------------------------------------------------------------------
/faq-accordion/style.css:
--------------------------------------------------------------------------------
1 | body, h1, p {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | body{
7 | font-family: 'Arial', sans-serif;
8 | background-color: #f7f7f7;
9 | display: flex;
10 | justify-content: center;
11 | align-items: center;
12 | height: 100vh;
13 | }
14 |
15 | .accordion-container{
16 | background-color: #fff;
17 | border-radius: 8px;
18 | box-shadow: 0 4px 6px rgba(0,0,0,0.1);
19 | width: 100%;
20 | max-width: 600px;
21 | }
22 |
23 | .accordion-item{
24 | border-bottom: 1px solid #ddd;
25 | }
26 |
27 | .accordion-header{
28 | background-color: #dedede;
29 | color: black;
30 | cursor: pointer;
31 | padding: 15px;
32 | width: 100%;
33 | text-align: left;
34 | border: none;
35 | outline: none;
36 | font-size: 16px;
37 | transition: background-color 0.3s ease;
38 | }
39 |
40 | .accordion-header:hover{
41 | background-color: #bababa;
42 | }
43 |
44 | .accordion-content{
45 | background-color: #f4f4f4;
46 | display: none;
47 | overflow: hidden;
48 | padding: 0 15px;
49 | max-height: 0;
50 | transition: max-height 0.3s ease, padding 0.3s ease;
51 | }
52 |
53 | .accordion-content p {
54 | padding: 15px 0;
55 | color: #2c3e50;
56 | }
57 |
58 | .accordion-header.active + .accordion-content{
59 | display: block;
60 | max-height: 150px;
61 | padding: 15px;
62 | }
--------------------------------------------------------------------------------
/number-guessing-game/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Arial', sans-serif;
3 | background-color: #f0f8ff;
4 | margin: 0;
5 | padding: 0;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | height: 100vh;
10 | }
11 |
12 | .game-container{
13 | text-align: center;
14 | background-color: #ffffff;
15 | padding: 30px;
16 | border-radius: 10px;
17 | box-shadow: 0 8px 15px rgba(0,0,0,0.1);
18 | max-width: 400px;
19 | width: 90%;
20 | }
21 |
22 | h1 {
23 | font-size: 2em;
24 | color: #333333;
25 | margin-bottom: 20px;
26 | }
27 | input {
28 | padding: 10px;
29 | font-size: 1.2em;
30 | border: 2px solid #00aaff;
31 | border-radius: 5px;
32 | width: 80%;
33 | margin-bottom: 20px;
34 | box-sizing: border-box;
35 | }
36 |
37 | button{
38 | background-color: #00aaff;
39 | color: white;
40 | padding: 10px 20px;
41 | font-size: 1em;
42 | border: none;
43 | border-radius: 5px;
44 | cursor: pointer;
45 | margin-top: 10px;
46 | transition: background-color 0.3s ease;
47 | }
48 |
49 | button:hover{
50 | background-color: #0077cc;
51 | }
52 | #message{
53 | font-size: 1.2em;
54 | color: #333333;
55 | margin-top: 20px;
56 | }
57 |
58 | #restartButton{
59 | background-color: #28a745;
60 | }
61 |
62 | #restartButton:hover{
63 | background-color: #218838;
64 | }
--------------------------------------------------------------------------------
/count-down-timer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Countdown Timer
7 |
8 |
9 |
10 |
11 |
12 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/random-quote-generator/style.css:
--------------------------------------------------------------------------------
1 | /* Basic styling for the body */
2 | body {
3 | font-family: 'Arial', sans-serif;
4 | background-color: #f5f5f5;
5 | margin: 0;
6 | padding: 0;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | height: 100vh;
11 | }
12 | .quote-container{
13 | text-align: center;
14 | background-color: #ffffff;
15 | padding: 40px;
16 | border-radius: 12px;
17 | box-shadow: 0 8px 20px rgba(0,0,0,0.1);
18 | max-width: 600px;
19 | width: 90%;
20 | }
21 |
22 | /* Styling for the Title */
23 | h1{
24 | font-size: 2em;
25 | color: #333333;
26 | margin-bottom: 20px;
27 | }
28 |
29 | /* Styling for the box displaying the quote */
30 | .quote-box{
31 | padding: 20px;
32 | margin: 20px 0;
33 | background-color: #e0f7fa;
34 | border-radius: 8px;
35 | box-shadow: 0 4px 10px rgba(0,0,0,0.1);
36 | }
37 | /* Styling for the quote text */
38 | #quote{
39 | font-size: 1.5em;
40 | color: #00796b;
41 | margin-bottom: 10px;
42 | }
43 | /* Styling Author Name */
44 | #author{
45 | font-size: 1.2em;
46 | color: #004d40;
47 | font-style: italic;
48 | }
49 |
50 | button{
51 | background-color: #05d9c0;
52 | color: whilte;
53 | padding: 12px 24px;
54 | border: none;
55 | border-radius: 8px;
56 | cursor: pointer;
57 | font-size: 1em;
58 | transition: background-color 0.3s ease;
59 | }
60 |
61 | /* Hover Effect for the button */
62 | button:hover {
63 | background-color: #04b799;
64 | }
--------------------------------------------------------------------------------
/quiz-app/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Arial', sans-serif;
3 | background-color: #f5f5f5;
4 | margin: 0;
5 | padding: 0;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | height: 100vh;
10 | }
11 |
12 | .quiz-container{
13 | background-color: #ffffff;
14 | padding: 20px;
15 | border-radius: 10px;
16 | box-shadow: 0 8px 10px rgba(0,0,0,0.1);
17 | width: 100%;
18 | max-width: 600px;
19 | text-align: center;
20 | }
21 |
22 | h1{
23 | font-size: 2em;
24 | color: #333;
25 | margin-bottom: 20px;
26 | }
27 |
28 | .question-container{
29 | background-color: #e0f7fa;
30 | padding: 15px;
31 | border-radius: 8px;
32 | margin-bottom: 20px;
33 | box-shadow: 0 4px 8px rgba(0,0,0,0.1);
34 | }
35 |
36 | .answer-buttons{
37 | display: grid;
38 | gap: 10px;
39 | margin-bottom: 20px;
40 | }
41 |
42 | button{
43 | padding: 10px;
44 | font-size: 1em;
45 | background-color: #00bcd4;
46 | color: white;
47 | border: none;
48 | border-radius: 5px;
49 | cursor: pointer;
50 | transition: background-color 0.3s ease;
51 | }
52 | button:hover{
53 | background-color: #0097a7;
54 | }
55 |
56 | .next-btn, .restart-btn{
57 | background-color: #ff9800;
58 | }
59 |
60 | .next-btn:hover, .restart-btn:hover{
61 | background-color: #f57c00;
62 | }
63 |
64 | .result-container{
65 | text-align: center;
66 | }
67 |
68 | #score{
69 | font-size: 1.5em;
70 | margin-bottom: 20px;
71 | color: #333;
72 | }
--------------------------------------------------------------------------------
/random-quote-generator/script.js:
--------------------------------------------------------------------------------
1 | // Array that store a list of quotes and their autho
2 | const quotes = [
3 | { text: "The only way to do great work is to love what you do.", author: "Steve Jobs" },
4 | { text: "Success is not final, failure is not fatal: It is the courage to continue that counts.", author: "Winston Churchill" },
5 | { text: "Believe you can and you’re halfway there.", author: "Theodore Roosevelt" },
6 | { text: "Act as if what you do makes a difference. It does.", author: "William James" },
7 | { text: "You are never too old to set another goal or to dream a new dream.", author: "C.S. Lewis" },
8 | { text: "Your time is limited, so don’t waste it living someone else’s life.", author: "Steve Jobs" }
9 | ];
10 |
11 | // Get HTML elements by their id
12 | const quoteText = document.getElementById('quote')
13 | const quoteAuthor = document.getElementById('author')
14 | const newQuoteButton = document.getElementById('new-quote')
15 |
16 | // function to generate a random quote
17 | function generateQuote(){
18 | // Get a random index from the quotes array
19 | const randomIndex = Math.floor(Math.random() * quotes.length)
20 | const randomQuote = quotes[randomIndex]
21 |
22 | // Update the quote text and author in the Element HTML
23 | quoteText.textContent = `"${randomQuote.text}"`
24 | quoteAuthor.textContent = `- ${randomQuote.author}`
25 |
26 | }
27 |
28 | // Add Event Listener for the button,
29 | newQuoteButton.addEventListener('click', generateQuote)
30 |
31 | // Call generate quote when page first loaded
32 | generateQuote()
--------------------------------------------------------------------------------
/count-down-timer/style.css:
--------------------------------------------------------------------------------
1 | /* Basic Styling for the body */
2 | body{
3 | font-family: 'Aria', sans-serif;
4 | background-color: #f0f8ff;
5 | margin: 0;
6 | padding: 0;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | height: 100vh;
11 | }
12 | /* Main container for the timer */
13 | .timer-container{
14 | text-align: center;
15 | background-color: #ffffff;
16 | padding: 30px;
17 | border-radius: 10px;
18 | box-shadow: 0 8px 15px rgba(0,0,0,0.1);
19 | max-width: 500px;
20 | width: 90%;
21 | }
22 |
23 | /* Styling for the title */
24 | h1{
25 | font-size: 2.5em;
26 | color: #333333;
27 | margin-bottom: 20px;
28 | }
29 |
30 | /* Contdown display */
31 | .countdown{
32 | font-size: 2em;
33 | color: #333333;
34 | margin-bottom: 20px;
35 | }
36 |
37 | /* Styling for inputs and button */
38 | .input-container{
39 | display: flex;
40 | justify-content: center;
41 | align-items: center;
42 | gap: 10px;
43 | }
44 | input{
45 | padding: 10px;
46 | font-size: 1.2em;
47 | border: 2px solid #00aaff;
48 | border-radius: 5px;
49 | width: 80px;
50 | text-align: center;
51 | box-sizing: border-box;
52 | }
53 |
54 | button{
55 | background-color: #00aaff;
56 | color: white;
57 | padding: 10px 20px;
58 | font-size: 1em;
59 | border: none;
60 | border-radius: 5px;
61 | cursor: pointer;
62 | transition: background-color 0.3s ease;
63 | }
64 |
65 | /* Styling for button Hover Effects */
66 | button:hover{
67 | background-color: #0077cc;
68 | }
--------------------------------------------------------------------------------
/calculator/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | box-sizing: border-box;
3 | }
4 |
5 | body{
6 | font-family: 'Roboto', sans-serif;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | height: 100vh;
11 | background-color: #f4f4f9;
12 | margin: 0;
13 | }
14 |
15 | .calculator{
16 | width: 320px;
17 | background-color: #ffffff;
18 | border-radius: 12px;
19 | box-shadow: 0 10 20px rgba(0,0,0,0.1);
20 | padding: 20px;
21 | }
22 | .calculator-screen{
23 | height: 80px;
24 | background-color: #252525;
25 | border-radius: 8px;
26 | display: flex;
27 | align-items: center;
28 | justify-content: center;
29 | padding-right: 20px;
30 | margin-bottom: 20px;
31 | }
32 | .calculator-display{
33 | width: 100%;
34 | height: 100%;
35 | font-size: 36px;
36 | color: white;
37 | border: none;
38 | background-color: transparent;
39 | text-align: right;
40 | outline: none;
41 | }
42 | .calculator-keys{
43 | display: grid;
44 | grid-template-columns: repeat(4,1fr);
45 | grid-gap: 10px;
46 | }
47 |
48 | button{
49 | height: 60px;
50 | font-size: 24px;
51 | border-radius: 8px;
52 | border: none;
53 | background-color: #eaeaea;
54 | transition: background-color 0.3s ease;
55 | cursor: pointer;
56 | }
57 | button:hover{
58 | background-color: #d4d4d4;
59 | }
60 | .operator{
61 | background-color: #f1c40f;
62 | }
63 | .equal-sign{
64 | background-color: #1e90ff;
65 | color: white;
66 | }
67 | .zero{
68 | grid-column: span 2;
69 | }
70 | .all-clear{
71 | background-color: #ff3b30;
72 | }
--------------------------------------------------------------------------------
/carousel-image-slider/script.js:
--------------------------------------------------------------------------------
1 | // Get Element HTML
2 |
3 | const carouselSlide = document.querySelector('.carousel-slide') // container for all image
4 |
5 | const carouselImages = document.querySelectorAll('.carousel-slide img')
6 |
7 | const prevBtn = document.querySelector('.prev-btn')
8 | const nextBtn = document.querySelector('.next-btn')
9 |
10 | const indicators = document.querySelectorAll('.indicator')
11 |
12 | let currentIndex = 0 // state current index
13 | const totalImages = carouselImages.length
14 |
15 | let autoSlideInterval; // variable to save interval for auto slide
16 |
17 | function updateCarousel(){
18 | carouselSlide.style.transform = `translateX(${-currentIndex *100}%)`
19 |
20 | //update active indicators
21 | indicators.forEach((indicator, index) => {
22 | indicator.classList.toggle('active', index === currentIndex)
23 | })
24 | }
25 |
26 | function nextSlide(){
27 | currentIndex = (currentIndex + 1) % totalImages
28 | updateCarousel()
29 | resetAutoSlide()
30 | }
31 |
32 | function prevSlide(){
33 | currentIndex = (currentIndex - 1 + totalImages) % totalImages
34 | updateCarousel()
35 | resetAutoSlide()
36 | }
37 |
38 | function resetAutoSlide(){
39 | clearInterval(autoSlideInterval)
40 |
41 | autoSlideInterval = setInterval(nextSlide, 5000)
42 | }
43 |
44 | // add event listener for next
45 | nextBtn.addEventListener('click', nextSlide)
46 |
47 | // add event listener for prev
48 | prevBtn.addEventListener('click', prevSlide)
49 |
50 | autoSlideInterval = setInterval(nextSlide, 5000)
51 |
52 | // add event listener for indicators
53 |
54 | indicators.forEach((indicator, index) => {
55 | indicator.addEventListener('click', () => {
56 | currentIndex = index
57 | updateCarousel()
58 | resetAutoSlide()
59 | })
60 | })
61 |
62 |
--------------------------------------------------------------------------------
/audio-app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Custom Audio Player with Playlist
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
27 |
28 |
No Track Selected
29 |
30 |
31 |
32 |
33 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/calculator/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Calculator Apps
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/shopping-cart/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Shopping Cart
7 |
8 |
9 |
10 |
11 |
12 | My Store
13 |
14 | 🛒 0
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
×
29 |
Shopping Cart
30 |
33 |
34 | Total: $0.00
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
×
43 |
![Product Image]()
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/number-guessing-game/script.js:
--------------------------------------------------------------------------------
1 | let randomNumber = Math.floor(Math.random() * 100) + 1
2 |
3 | let attempts = 0
4 |
5 | // Get Element HTML
6 | const guessInput = document.getElementById('guessInput')
7 | const guessButton = document.getElementById('guessButton')
8 | const message = document.getElementById('message')
9 | const restartButton = document.getElementById('restartButton')
10 |
11 | function checkGuess() {
12 | const userGuess = Number(guessInput.value)
13 | // after check user guess, attempts ++
14 | attempts++
15 |
16 | if(userGuess === randomNumber){
17 | message.textContent = `Congratulations! You guessed the Number ${randomNumber} correctly in ${attempts} attempts.`
18 | message.style.color = '#28a745'
19 | endGame()
20 | } else if (userGuess > randomNumber){
21 | message.textContent = "Too high! Try Again."
22 | message.style.color = "#dc3545"
23 | } else if (userGuess < randomNumber){
24 | message.textContent = "Too low! Try Again."
25 | message.style.color = "#dc3545"
26 | }
27 |
28 | guessInput = ''
29 | guessInput.focus()
30 | }
31 |
32 | function endGame(){
33 | guessInput.disabled = true
34 | guessButton.disabled = true
35 | restartButton.style.display = 'inline'
36 | }
37 |
38 | function resetGame() {
39 | attempts = 0
40 | randomNumber = Math.floor(Math.random() * 100) + 1
41 | guessInput.disabled = false
42 | guessButton.disabled = false
43 | message.textContent = 'Good Luck! Start Guessing . . .'
44 | message.style.color = '#333333'
45 | restartButton.style.display = "none"
46 | guessInput.value = ''
47 | guessInput.focus()
48 | }
49 |
50 | guessButton.addEventListener('click', checkGuess)
51 |
52 | restartButton.addEventListener('click', resetGame)
53 |
54 | guessInput.addEventListener('keydown', function(event) {
55 | if (event.key === 'Enter'){
56 | checkGuess()
57 | }
58 | })
--------------------------------------------------------------------------------
/weather-app/script.js:
--------------------------------------------------------------------------------
1 | /** @format */
2 |
3 | const apiKey = '3c02d6c14753359e454ae7d2c9b6dce0';
4 |
5 | // ambil element html yang diperlukan
6 |
7 | const locationElement = document.getElementById('location');
8 | const temperatureElement = document.getElementById('temperature');
9 | const descriptionElement = document.getElementById('description');
10 | const weatherIconElement = document.getElementById('weather-icon');
11 |
12 | // function untuk mendapatkan cuaca dari openweather
13 | async function getWeather(latitude, longitude) {
14 | const apiURL = `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&units=metric&appid=${apiKey}`;
15 |
16 | try {
17 | const response = await fetch(apiURL);
18 | const data = await response.json();
19 |
20 | locationElement.textContent = `${data.name}, ${data.sys.country}`
21 | temperatureElement.textContent = `Temperature: ${data.main.temp} °C`
22 | descriptionElement.textContent = `Description: ${data.weather[0].description}`
23 |
24 | const iconCode = data.weather[0].icon
25 | weatherIconElement.innerHTML = `
`
26 |
27 |
28 | } catch (error) {
29 | console.error('Error fetching weather data: ');
30 | alert('Failed to fetch weather data. Please try again later');
31 | }
32 | }
33 |
34 | function getLocation() {
35 | if (navigator.geolocation) {
36 | navigator.geolocation.getCurrentPosition((position) => {
37 | const latitude = position.coords.latitude
38 | const longitude = position.coords.longitude
39 | getWeather(latitude, longitude)
40 | }, error => {
41 | alert('Failed to get your location. Please Enable location services')
42 | });
43 | } else {
44 | alert('Geolocation is not supported by your browser')
45 | }
46 | }
47 |
48 | // memanggil fungsi getLocation ketika halaman dimuat
49 | window.onload = getLocation
50 |
--------------------------------------------------------------------------------
/paint-app/script.js:
--------------------------------------------------------------------------------
1 | // get element from the DOM
2 | const canvas = document.getElementById('canvas')
3 | const ctx = canvas.getContext('2d')
4 |
5 | const brushBtn = document.getElementById('brush')
6 | const eraserBtn = document.getElementById('eraser')
7 | const clearBtn = document.getElementById('clear')
8 | const colorPicker = document.getElementById('colorPicker')
9 |
10 | // set canvas
11 | canvas.width = 800
12 | canvas.height = 500
13 |
14 | // variable to store state of the tools
15 | let painting = false
16 | let erasing = false
17 | let currentColor = '#000000'
18 | let lineWidth = 5
19 |
20 | // function to startPainting
21 | function startPosition(e){
22 | painting= true
23 | draw(e) // function to draw on canvas
24 | }
25 |
26 | // function to stop painting
27 | function endPosition(e) {
28 | painting = false
29 | ctx.beginPath() // start new path,
30 | }
31 |
32 | // function to draw on canvas
33 | function draw (e){
34 | if(!painting) return
35 |
36 | ctx.lineWidth = lineWidth
37 | ctx.lineCap = 'round'
38 | ctx.strokeStyle = erasing ? '#ffffff' : currentColor
39 |
40 | ctx.lineTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop)
41 | ctx.stroke()
42 | ctx.beginPath()
43 | ctx.moveTo(e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop)
44 | }
45 |
46 | function selectBrush() {
47 | erasing = false
48 | brushBtn.classList.add('active')
49 | eraserBtn.classList.remove('active')
50 | }
51 |
52 | function selectEraser(){
53 | erasing = true;
54 | eraserBtn.classList.add('active')
55 | brushBtn.classList.remove('active')
56 | }
57 |
58 | function clearCanvas(){
59 | ctx.clearRect(0,0, canvas.width, canvas.height)
60 | }
61 |
62 | function changeColor(e){
63 | currentColor = e.target.value
64 | }
65 |
66 | // add event listener to each tool
67 | brushBtn.addEventListener('click', selectBrush)
68 | eraserBtn.addEventListener('click', selectEraser)
69 | clearBtn.addEventListener('click', clearCanvas)
70 | colorPicker.addEventListener('input', changeColor)
71 |
72 | canvas.addEventListener('mousedown', startPosition)
73 | canvas.addEventListener('mouseup', endPosition)
74 | canvas.addEventListener('mousemove', draw)
--------------------------------------------------------------------------------
/carousel-image-slider/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Image Carousel App
7 |
8 |
9 |
10 |
11 |
12 | Welcome to Project Carousel
13 | Follow for more project
14 |
15 |
16 |
17 |

18 |

19 |

20 |

21 |

22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/typing-speed-test/script.js:
--------------------------------------------------------------------------------
1 | /** @format */
2 |
3 | // ambil element html yang diperlukan dari "ID"
4 | const textToTypeElement = document.getElementById('text-to-type');
5 | const textToType = textToTypeElement.innerHTML.split(' ');
6 | const userInput = document.getElementById('user-input');
7 | const startButton = document.getElementById('start-button');
8 | const timeDisplay = document.getElementById('time');
9 | const wpmDisplay = document.getElementById('words-per-minute');
10 |
11 | console.log(textToType)
12 |
13 | let startTime;
14 | let timerInterval;
15 |
16 | // function to start test
17 | function startTest() {
18 | startTime = new Date();
19 | userInput.value = '';
20 | userInput.focus();
21 | timerInterval = setInterval(updateTimer, 1000);
22 | textToTypeElement.innerHTML = textToType
23 | .map((word) => `${word}`)
24 | .join(' ');
25 | }
26 |
27 | function updateTimer() {
28 | const currentTime = new Date();
29 | const elapsedTime = Math.floor((currentTime - startTime) / 1000);
30 | timeDisplay.innerText = elapsedTime;
31 | }
32 |
33 | function calculateWPM() {
34 | const wordsTyped = userInput.value.trim().split(/\s+/).length;
35 | const elapsedTime = Math.floor((new Date() - startTime) / 1000);
36 | const minutes = elapsedTime / 60;
37 | const wpm = Math.floor(wordsTyped / minutes);
38 | wpmDisplay.innerHTML = wpm;
39 | }
40 |
41 | function checkInput() {
42 | const typedText = userInput.value.trim().split(' ');
43 | const spans = textToTypeElement.querySelectorAll('span');
44 | typedText.forEach((word, index) => {
45 | if (spans[index]) {
46 | if (word === textToType[index]) {
47 | spans[index].className = 'correct';
48 | } else {
49 | spans[index].className = 'incorrect';
50 | }
51 | }
52 | });
53 |
54 | // hapus kelas jika pengguna menghapus tesk yang sudah diketik sebelumnya
55 | for (let i = typedText.length; i < spans.length; i++) {
56 | spans[i].className = '';
57 | }
58 | }
59 |
60 | function stopTest() {
61 | clearInterval(timerInterval);
62 | calculateWPM();
63 | }
64 |
65 | startButton.addEventListener('click', () => {
66 | startTest();
67 | });
68 |
69 | userInput.addEventListener('input', () => {
70 | checkInput();
71 | const typedText = userInput.value;
72 | if (typedText.trim() === textToType.join(' ')) {
73 | stopTest();
74 | }
75 | });
76 |
--------------------------------------------------------------------------------
/audio-app/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Arial', sans-serif;
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | height: 100vh;
7 | margin: 0;
8 | background-color: #e0f7fa;
9 | }
10 |
11 | .container{
12 | display: flex;
13 | background-color: #004d40;
14 | padding: 20px;
15 | border-radius: 10px;
16 | box-shadow: 0 4px 10px rgba(0,0,0,0.1);
17 | }
18 |
19 | .audio-player{
20 | display: flex;
21 | flex-direction: column;
22 | justify-content: center;
23 | align-items: center;
24 | padding-right: 20px;
25 | border-right: 2px solid #ffeb3b;
26 | }
27 | .audio-controls {
28 | display: flex;
29 | align-items: center;
30 | width: 300px;
31 | }
32 |
33 | .play-button {
34 | background-color: #ffeb3b;
35 | border: none;
36 | padding: 10px;
37 | border-radius: 50%;
38 | cursor: pointer;
39 | margin-right : 10px;
40 | }
41 |
42 | .progress-container {
43 | flex-grow: 1;
44 | height: 10px;
45 | background-color: #00796b;
46 | border-radius: 5px;
47 | overflow: hidden;
48 | position: relative;
49 | }
50 |
51 | #progress-bar{
52 | height: 100%;
53 | background-color: #ffeb3b;
54 | width: 0.5%;
55 | min-width: 2px;
56 | transition: width 0.1 ease;
57 | }
58 |
59 | #current-track {
60 | margin-top: 10px;
61 | color: #ffeb3b;
62 | }
63 |
64 | .audio-list{
65 | padding-left: 20px;
66 | display: flex;
67 | flex-direction: column;
68 | }
69 |
70 | .upload-label{
71 | display: block;
72 | background-color: #ffeb3b;
73 | color: #00796b;
74 | padding: 5px;
75 | text-align: center;
76 | border-radius: 5px;
77 | cursor: pointer;
78 | margin-bottom: 10px;
79 | font-weight: bold;
80 | }
81 |
82 | #audio-upload{
83 | display: none;
84 | }
85 |
86 | #playlist{
87 | height: 200px;
88 | overflow-y: auto;
89 | padding: 0;
90 | margin: 0;
91 | scrollbar-width: thin;
92 | scrollbar-color: rgba(255,255,255,0.5) transparent;
93 | }
94 |
95 | #playlist::-webkit-scrollbar{
96 | width: 6px;
97 | }
98 | #playlist::-webkit-scrollbar-thumb{
99 | background-color: rgba(255,255,255,0.5);
100 | border-radius: 10px; /* agar scollbar bulat */
101 | }
--------------------------------------------------------------------------------
/carousel-image-slider/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | box-sizing: border-box;
3 | }
4 |
5 | body{
6 | font-family: 'Aria', sans-serif;
7 | margin: 0;
8 | padding: 0;
9 | background-color: #f0f0f0;
10 | display: flex;
11 | justify-content: center;
12 | align-items: center;
13 | height: 100vh;
14 | overflow: hidden;
15 | }
16 |
17 | .container{
18 | display: flex;
19 | flex-direction: column;
20 | }
21 |
22 | header{
23 | text-align: center;
24 | margin-bottom: 30px;
25 | }
26 | header h1{
27 | color: #333;
28 | font-size: 2em;
29 | margin-bottom: 10px;
30 | }
31 |
32 | header h2{
33 | color: #666;
34 | font-size: 1em;
35 | font-weight: 400;
36 | }
37 |
38 | .carousel-container {
39 | position: relative;
40 | max-width: 1000px;
41 | width: 100%;
42 | overflow: hidden;
43 | border-radius: 15px;
44 | box-shadow: 0 10px 30px rgba(0,0,0,0.1);
45 | }
46 | .carousel-slide{
47 | display: flex;
48 | transition: transform 0.4s ease-in-out;
49 | }
50 |
51 | .carousel-slide img{
52 | width: 100%;
53 | border-radius: 15px;
54 | }
55 |
56 | .prev-btn, .next-btn{
57 | position: absolute;
58 | top: 50%;
59 | transform: translateY(-50%);
60 | background-color: rgba(0,0,0,0.5);
61 | color: white;
62 | border: none;
63 | font-size: 30px;
64 | cursor: pointer;
65 | padding: 10px;
66 | border-radius: 50%;
67 | z-index: 1;
68 | }
69 |
70 | .prev-btn{
71 | left: 10px;
72 | }
73 |
74 | .next-btn{
75 | right: 10px;
76 | }
77 |
78 | .prev-btn:hover, .next-btn:hover{
79 | background-color: rgba(0,0,0,0.8);
80 | }
81 |
82 | .carousel-indicators {
83 | position: absolute;
84 | bottom: 20px;
85 | left: 50%;
86 | transform: translateX(-50%);
87 | display: flex;
88 | justify-content: center;
89 | gap: 10px;
90 | }
91 | .indicator{
92 | width: 12px;
93 | height: 12px;
94 | background-color: rgba(255,255,255,0.5);
95 | border-radius: 50%;
96 | cursor: pointer;
97 | transition: background-color 0.3s ease;
98 | }
99 |
100 | .indicator.active{
101 | background-color: rgba(255,255,255,0.9);
102 | }
103 | .indicator:hover{
104 | background-color: rgba(255,255,255,0.7);
105 | }
106 |
107 | /* Responsive */
108 |
109 | @media (max-width: 768px){
110 | .prev-btn, .next-btn {
111 | font-size: 24px;
112 | padding: 8px;
113 | }
114 | .indicator {
115 | width: 10px;
116 | height: 10px;
117 | }
118 | }
--------------------------------------------------------------------------------
/count-down-timer/script.js:
--------------------------------------------------------------------------------
1 | // Getting the HTML elements
2 | const countdownElement = document.getElementById('countdown')
3 | const daysElement = document.getElementById('days')
4 | const hoursElement = document.getElementById('hours')
5 | const minutesElement = document.getElementById('minutes')
6 | const secondsElement = document.getElementById('seconds')
7 | const inputHours = document.getElementById('inputHours')
8 | const inputMinutes = document.getElementById('inputMinutes')
9 | const inputSeconds = document.getElementById('inputSeconds')
10 | const startButton = document.getElementById('startButton')
11 |
12 | // varible countdownInterval
13 | let countdownInterval;
14 |
15 | // function to start the timer
16 | function startTimer(){
17 | // Get the input values from user
18 | let hours = parseInt(inputHours.value) || 0
19 | let minutes = parseInt(inputMinutes.value) || 0
20 | let seconds = parseInt(inputSeconds.value) || 0
21 |
22 | // convert the total time into seconds
23 | let totalTimeInSeconds = hours * 3600 + minutes * 60 + seconds
24 |
25 | // if no time is input, stop the function
26 | if (totalTimeInSeconds <=0){
27 | alert("Please enter a valid time.")
28 | return
29 | }
30 | // clear the input after the timer starts
31 | inputHours.value = ''
32 | inputMinutes.value = ''
33 | inputSeconds.value = ''
34 |
35 | // function to update the time display every seconds
36 | countdownInterval = setInterval(()=> {
37 | // calculate remaining days, hours, minutes, and seconds
38 | const days = Math.floor(totalTimeInSeconds/86400)
39 | const hours = Math.floor((totalTimeInSeconds % 86400) / 3600)
40 | const minutes = Math.floor((totalTimeInSeconds%3600)/60)
41 | const seconds = Math.floor((totalTimeInSeconds % 60))
42 |
43 | //Update the HTML element display
44 | daysElement.textContent = days.toString().padStart(2,'0')
45 | hoursElement.textContent = hours.toString().padStart(2,'0')
46 | minutesElement.textContent = minutes.toString().padStart(2,'0')
47 | secondsElement.textContent = seconds.toString().padStart(2,'0')
48 |
49 | // Decrease the total time by one seconds
50 | totalTimeInSeconds--
51 |
52 | // Stop the timer if time runs out
53 | if(totalTimeInSeconds < 0) {
54 | clearInterval(countdownInterval)
55 | alert("Time's up!")
56 | }
57 |
58 | }, 1000 //miliseconds
59 | )
60 | }
61 |
62 | // add Event Listener for the start button
63 | startButton.addEventListener('click', ()=> {
64 | // stop any running timer
65 | clearInterval(countdownInterval)
66 | // start a new timer
67 | startTimer()
68 | })
--------------------------------------------------------------------------------
/faq-accordion/script.js:
--------------------------------------------------------------------------------
1 | // list faq
2 | const faqData = [
3 | {
4 | question: "What is HTML?",
5 | answer: "HTML stands for HyperText Markup Language. It is the standard language for creating web pages."
6 | },
7 | {
8 | question: "What is CSS?",
9 | answer: "CSS stands for Cascading Style Sheets. It is used to style and layout web pages."
10 | },
11 | {
12 | question: "What is JavaScript?",
13 | answer: "JavaScript is a programming language that is used to create dynamic and interactive effects on web pages."
14 | }
15 | ];
16 |
17 | // get accordion Container
18 | const accordionContainer = document.getElementById('accordion')
19 |
20 | // create function to generate faqData from array faqData
21 |
22 | function generateAccordionItems(faqData){
23 | faqData.forEach(item => {
24 | const accordionItem = document.createElement('div')
25 |
26 | accordionItem.classList.add('accordion-item')
27 |
28 | //create element for header
29 | const header = document.createElement('button')
30 | header.classList.add('accordion-header')
31 | header.textContent = item.question
32 |
33 | //create element for content
34 | const content = document.createElement('div')
35 | content.classList.add('accordion-content')
36 |
37 | const contentText = document.createElement('p')
38 | contentText.textContent = item.answer
39 |
40 | // insert element to HTML
41 | content.appendChild(contentText)
42 | accordionItem.appendChild(header)
43 | accordionItem.appendChild(content)
44 |
45 | // add accordion item to accordion container
46 | accordionContainer.appendChild(accordionItem)
47 | })
48 | }
49 | // call function generate faq
50 | generateAccordionItems(faqData)
51 |
52 |
53 |
54 | // get element accordion header
55 | const accordionHeaders = document.querySelectorAll('.accordion-header')
56 |
57 | // add event listener for accordion
58 | accordionHeaders.forEach(header => {
59 | header.addEventListener('click', () => {
60 | header.classList.toggle('active')
61 | const accordionContent = header.nextElementSibling
62 |
63 | if(header.classList.contains('active')) {
64 | accordionContent.style.maxHeight = accordionContent.scrollHeight + 'px'
65 | } else {
66 | accordionContent.style.maxHeight = 0
67 | }
68 |
69 | accordionHeaders.forEach(otherHeader => {
70 | if(otherHeader !== header && otherHeader.classList.contains('active')) {
71 | otherHeader.classList.remove('active')
72 | otherHeader.nextElementSibling.style.maxHeight = 0
73 | }
74 | })
75 | })
76 | })
77 |
--------------------------------------------------------------------------------
/shopping-cart/styles.css:
--------------------------------------------------------------------------------
1 | /* Styling dasar untuk body */
2 | body {
3 | font-family: Arial, sans-serif;
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: border-box;
7 | }
8 |
9 | /* Styling untuk header, termasuk cart icon */
10 | header {
11 | display: flex;
12 | justify-content: space-between;
13 | align-items: center;
14 | padding: 20px;
15 | background-color: #333;
16 | color: white;
17 | }
18 |
19 | /* Styling untuk ikon cart */
20 | .cart-icon {
21 | cursor: pointer;
22 | }
23 |
24 | /* Styling untuk bagian utama (main) */
25 | main {
26 | padding: 20px;
27 | }
28 |
29 | /* Grid layout untuk daftar produk */
30 | #product-list {
31 | display: grid;
32 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
33 | gap: 20px;
34 | }
35 |
36 | /* Styling untuk setiap kartu produk */
37 | .product-card {
38 | border: 1px solid #ccc;
39 | border-radius: 5px;
40 | padding: 15px;
41 | text-align: center;
42 | }
43 |
44 | /* Menampilkan gambar produk dalam kartu produk */
45 | img {
46 | max-width: 100%;
47 | height: auto;
48 | border-radius: 5px;
49 | }
50 |
51 | /* Styling untuk tombol */
52 | button {
53 | padding: 10px 20px;
54 | margin-top: 10px;
55 | cursor: pointer;
56 | border: none;
57 | border-radius: 5px;
58 | background-color: #333;
59 | color: white;
60 | }
61 |
62 | /* Hover effect untuk tombol */
63 | button:hover {
64 | background-color: #555;
65 | }
66 |
67 | /* Styling untuk modal */
68 | .modal {
69 | display: none;
70 | position: fixed;
71 | z-index: 1;
72 | left: 0;
73 | top: 0;
74 | width: 100%;
75 | height: 100%;
76 | overflow: auto;
77 | background-color: rgba(0, 0, 0, 0.5);
78 | }
79 |
80 | /* Konten dalam modal */
81 | .modal-content {
82 | background-color: white;
83 | margin: 10% auto;
84 | padding: 20px;
85 | border-radius: 5px;
86 | width: 80%;
87 | max-width: 500px;
88 | position: relative;
89 | }
90 |
91 | /* Tombol close untuk modal */
92 | .close {
93 | position: absolute;
94 | top: 10px;
95 | right: 20px;
96 | color: black;
97 | font-size: 30px;
98 | font-weight: bold;
99 | cursor: pointer;
100 | }
101 |
102 | /* Hover effect untuk tombol close */
103 | .close:hover {
104 | color: red;
105 | }
106 |
107 | /* Styling untuk daftar item dalam cart */
108 | #cart-items {
109 | list-style: none;
110 | padding: 0;
111 | margin: 0;
112 | }
113 |
114 | /* Styling untuk total harga dalam cart */
115 | .total-price {
116 | margin-top: 20px;
117 | font-size: 18px;
118 | font-weight: bold;
119 | text-align: right;
120 | }
121 |
--------------------------------------------------------------------------------
/todo-list/style.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: 'Arial', sans-serif;
3 | background-color: #f0f4f8;
4 | display: flex;
5 | align-items: center;
6 | justify-content: center;
7 | height: 100vh;
8 | margin: 0;
9 | }
10 | .container{
11 | background-color: white;
12 | border-radius: 10px;
13 | box-shadow: 0 10px 20px rgba(0,0,0,0.1);
14 | padding: 20px;
15 | width: 400px;
16 | }
17 | h1{
18 | text-align: center;
19 | color: #333;
20 | }
21 | #new-task{
22 | width: 80%;
23 | padding: 10px;
24 | margin-bottom: 20px;
25 | border: 1px solid #ddd;
26 | border-radius: 5px;
27 | outline: none;
28 | }
29 | #add-task-btn{
30 | background: #28a745;
31 | padding: 10px 15px;
32 | color: white;
33 | border: none;
34 | cursor: pointer;
35 | border-radius: 5px;
36 | font-weight: bold;
37 | }
38 | #add-task-btn:hover{
39 | background: #218838;
40 | }
41 | #todo-list{
42 | list-style: none;
43 | padding: 0;
44 | }
45 | li{
46 | display: flex;
47 | justify-content: space-between;
48 | align-items: center;
49 | padding: 10px;
50 | margin-bottom: 10px;
51 | background: #f8f9fa;
52 | border-radius: 5px;
53 | box-shadow: 0 2px 5px rgba(0,0,0,0.1);
54 | }
55 | li span{
56 |
57 | flex: 1;
58 | font-size: 16px;
59 | }
60 | .buttons{
61 | display: flex;
62 | gap: 5px;
63 | }
64 | button{
65 | padding: 5px 10px;
66 | border: none;
67 | cursor: pointer;
68 | border-radius: 3px ;
69 | font-weight: bold;
70 | }
71 | .edit-btn{
72 | background: #007bff;
73 | color: white;
74 | }
75 | .edit-btn:hover{
76 | background: #0056b3;
77 | }
78 | .delete-btn{
79 | background: #dc3545;
80 | color: white;
81 | }
82 | .delete-btn:hover{
83 | background: #c83333;
84 | }
85 | .modal{
86 | display: none;
87 | position: fixed;
88 | top: 0;
89 | left: 0;
90 | width: 100%;
91 | height: 100%;
92 | justify-content: center;
93 | align-items: center;
94 | background: rgba(0,0,0,0.5);
95 |
96 | }
97 | .modal-content{
98 | background: white;
99 | padding: 20px;
100 | border-radius: 5px;
101 | width: 300px;
102 | text-align: center;
103 | }
104 | .modal input{
105 | width: 80%;
106 | padding: 10px;
107 | margin-bottom: 10px;
108 | border: 1px solid #ddd;
109 | border-radius: 5px;
110 | outline: none;
111 | }
112 | .modal button{
113 | padding: 10px 15px;
114 | margin: 5px;
115 | }
116 | .close-modal-btn{
117 | background: #dc3545;
118 | color: white;
119 | border: none;
120 | cursor: pointer;
121 | border-radius: 5px;
122 | }
123 | .save-modal-btn{
124 | background: #28a745;
125 | color: white;
126 | border: none;
127 | cursor: pointer;
128 | border-radius: 5px;
129 | }
--------------------------------------------------------------------------------
/todo-list/script.js:
--------------------------------------------------------------------------------
1 | let currentEditElement = null
2 |
3 | document.addEventListener('DOMContentLoaded', () => {
4 | loadTasksFromLocalStorage()
5 | })
6 |
7 | function loadTasksFromLocalStorage(){
8 | let tasks = JSON.parse(localStorage.getItem('tasks')) || []
9 | tasks.forEach(task => {
10 | const li = createTaskElement(task)
11 | document.getElementById('todo-list').appendChild(li)
12 | })
13 | }
14 |
15 | function createTaskElement(task){
16 | const li = document.createElement('li')
17 | const span = document.createElement('span')
18 | span.textContent = task
19 |
20 | const editBtn = document.createElement('button')
21 | editBtn.textContent = 'Edit'
22 | editBtn.classList.add('edit-btn')
23 | editBtn.onclick = () => openModal(li,span)
24 |
25 | const deleteBtn = document.createElement('button')
26 | deleteBtn.textContent = 'Delete'
27 | deleteBtn.classList.add('delete-btn')
28 | deleteBtn.onclick = () => {
29 | li.remove();
30 | deleteTaskFromLocalStorage(task)
31 | }
32 |
33 | const buttons = document.createElement('div')
34 | buttons.classList.add('buttons')
35 | buttons.appendChild(editBtn)
36 | buttons.appendChild(deleteBtn)
37 |
38 |
39 | li.appendChild(span)
40 | li.appendChild(buttons)
41 |
42 | return li
43 | }
44 | function openModal(li,span){
45 | currentEditElement = {li, span}
46 | document.getElementById('edit-task-input').value = span.textContent
47 | document.getElementById('editModal').style.display = 'flex'
48 | }
49 |
50 | function closeModal(){
51 | document.getElementById('editModal').style.display = 'none'
52 | }
53 |
54 | function addTask(){
55 | const taskInput = document.getElementById('new-task')
56 | const task = taskInput.value.trim()
57 |
58 | if(task){
59 | const li = createTaskElement(task)
60 | document.getElementById('todo-list').appendChild(li)
61 |
62 | saveTaskToLocalStorage(task)
63 | taskInput.value = ''
64 | }
65 | }
66 |
67 | function saveTask(){
68 | const editedTask = document.getElementById('edit-task-input').value.trim()
69 | if(editedTask){
70 | const originalTask = currentEditElement.span.textContent
71 | currentEditElement.span.textContent = editedTask
72 | updateTaskInLocalStorage(originalTask, editedTask)
73 | closeModal()
74 | }
75 | }
76 | // handle localstorage
77 | function saveTaskToLocalStorage(task){
78 | let tasks = JSON.parse(localStorage.getItem('tasks')) || []
79 | tasks.push(task)
80 | localStorage.setItem('tasks', JSON.stringify(tasks))
81 | }
82 |
83 | function deleteTaskFromLocalStorage(task){
84 | let tasks = JSON.parse(localStorage.getItem('tasks')) || []
85 | tasks = tasks.filter(t => t !== task)
86 | localStorage.setItem('tasks', JSON.stringify(tasks))
87 | }
88 |
89 | function updateTaskInLocalStorage(originalTask, editedTask){
90 | let tasks = JSON.parse(localStorage.getItem('tasks')) || []
91 | const taskIndex = tasks.indexOf(originalTask)
92 | if(taskIndex > -1){
93 | tasks[taskIndex] = editedTask
94 | }
95 | localStorage.setItem('tasks', JSON.stringify(tasks))
96 | }
--------------------------------------------------------------------------------
/audio-app/script.js:
--------------------------------------------------------------------------------
1 | // ambil audio jika ada di local storage
2 |
3 | let playlist = JSON.parse(localStorage.getItem('playlist')) || []
4 |
5 | // ambil element dari dom, "ID"
6 | const audio = document.getElementById('audio')
7 | const playPauseButton = document.getElementById('play-pause')
8 | const playIcon = document.getElementById('play-icon')
9 | const pauseIcon = document.getElementById('pause-icon')
10 | const progressBar = document.getElementById('progress-bar')
11 | const playlistElement = document.getElementById('playlist')
12 | const audioUpload = document.getElementById('audio-upload')
13 | const currentTrack = document.getElementById('current-track')
14 |
15 | // fungsi untuk membuat list audio
16 | function createPlaylist(){
17 | playlistElement.innerHTML = ''
18 | playlist.forEach((track, index) => {
19 | const li = document.createElement('li')
20 | li.textContent = track.title
21 | li.dataset.src = track.src
22 |
23 | li.addEventListener('click', () => {
24 | audio.src = track.src
25 | audio.play()
26 | updatePlayPauseIcon()
27 |
28 | document.querySelectorAll('#playlist li').forEach(item => item.classList.remove('active'))
29 |
30 | li.classList.add('active');
31 |
32 | currentTrack.textContent = track.title
33 | })
34 |
35 | playlistElement.appendChild(li)
36 | });
37 | }
38 |
39 | function updatePlayPauseIcon(){
40 | if(audio.paused){
41 | playIcon.style.display = 'block'
42 | pauseIcon.style.display = 'none'
43 | } else {
44 | playIcon.style.display = 'none'
45 | pauseIcon.style.display = 'block'
46 | }
47 | }
48 |
49 | // fungsi untuk save playlist ke local storage
50 | function savePlaylist(){
51 | localStorage.setItem('playlist', JSON.stringify(playlist))
52 | }
53 |
54 | // inisialisasi playlist
55 | createPlaylist()
56 |
57 | // event listener untuk upload file audio
58 | audioUpload.addEventListener('change', (event) => {
59 | const files = Array.from(event.target.files)
60 | files.forEach(file => {
61 | const reader = new FileReader()
62 | reader.onload = function(e){
63 | const track = {
64 | title: file.name,
65 | src: e.target.result
66 | }
67 | playlist.push(track)
68 | console.log(playlist)
69 | createPlaylist()
70 | savePlaylist()
71 | }
72 | reader.readAsDataURL(file)
73 | })
74 | })
75 |
76 | // event listener ke play pause
77 | playPauseButton.addEventListener('click', () => {
78 | if(audio.paused) {
79 | audio.play()
80 | } else {
81 | audio.pause()
82 | }
83 | updatePlayPauseIcon()
84 | })
85 |
86 | // update progress bar saat audioo diputar
87 | audio.addEventListener('timeupdate', () => {
88 | const progress = (audio.currentTime / audio.duration) * 100
89 | progressBar.style.width = progress + '%'
90 | })
91 |
92 | // reset ketika audio berakhir
93 | audio.addEventListener('ended', () => {
94 | updatePlayPauseIcon()
95 | progressBar.style.width = '0'
96 | audio.pause()
97 | playIcon.style.display = 'block'
98 | pauseIcon.style.display = 'none'
99 | })
--------------------------------------------------------------------------------
/calculator/script.js:
--------------------------------------------------------------------------------
1 | const calculator = {
2 | displayValue: '0',
3 | firstOperand: null,
4 | waitingForSecondOperand: false,
5 | operator: null
6 | }
7 |
8 | function updateDisplay(){
9 | const display = document.querySelector('.calculator-display')
10 | display.value = calculator.displayValue
11 | }
12 |
13 | function inputDigit(digit){
14 | const {displayValue, waitingForSecondOperand} = calculator
15 |
16 | if(waitingForSecondOperand === true){
17 | calculator.displayValue = digit
18 | calculator.waitingForSecondOperand = false
19 | } else {
20 | calculator.displayValue = displayValue === '0' ? digit : displayValue + digit
21 | }
22 | updateDisplay()
23 | }
24 |
25 | function inputDecimal(dot){
26 | if(!calculator.displayValue.includes(dot)){
27 | calculator.displayValue += dot
28 | }
29 | }
30 |
31 | function handleOperator(nextOperator){
32 | const {firstOperand, displayValue, operator} = calculator
33 | const inputValue = parseFloat(displayValue)
34 |
35 | if(operator && calculator.waitingForSecondOperand){
36 | calculator.operator = nextOperator
37 | return
38 | }
39 |
40 | if(firstOperand === null && !isNaN(inputValue)){
41 | calculator.firstOperand = inputValue
42 | } else if (operator){
43 | const result = calculate(firstOperand, inputValue, operator)
44 | calculator.displayValue = `${parseFloat(result.toFixed(7))}`
45 | calculator.firstOperand = result
46 | }
47 |
48 | calculator.waitingForSecondOperand = true
49 | calculator.operator = nextOperator
50 |
51 | updateDisplay()
52 | }
53 |
54 | function calculate(firstOperand, secondOperand, operator){
55 | if(operator === '+'){
56 | return firstOperand + secondOperand
57 | } else if(operator === '-'){
58 | return firstOperand - secondOperand
59 | } else if(operator === '*'){
60 | return firstOperand * secondOperand
61 | } else if(operator === '/'){
62 | return firstOperand / secondOperand
63 | } else if(operator === '√'){
64 | return Math.sqrt(firstOperand)
65 | } else if (operator === '%') {
66 | return firstOperand / 100
67 | }
68 |
69 | return secondOperand
70 | }
71 |
72 | function resetCalculator(){
73 | calculator.displayValue = '0'
74 | calculator.firstOperand = null;
75 | calculator.waitingForSecondOperand = false
76 | calculator.operator = null
77 | updateDisplay()
78 | }
79 |
80 | function handleEqual(){
81 | const {firstOperand, displayValue, operator} = calculator
82 | const inputValue = parseFloat(displayValue)
83 |
84 | if(operator && !calculator.waitingForSecondOperand){
85 | const result = calculate(firstOperand, inputValue, operator)
86 | calculator.displayValue = `${parseFloat(result.toFixed(7))}`
87 | calculator.firstOperand = null
88 | calculator.operator = null
89 | calculator.waitingForSecondOperand = false
90 | updateDisplay()
91 | }
92 | }
93 |
94 | document.querySelector('.calculator-keys').addEventListener('click', (event) => {
95 | const {target} = event
96 |
97 | if(!target.matches('button')){
98 | return
99 | }
100 |
101 | if(target.classList.contains('operator')){
102 | handleOperator(target.value)
103 | return
104 | }
105 |
106 | if(target.classList.contains('decimal')){
107 | inputDecimal(target.value)
108 | return
109 | }
110 |
111 | if(target.classList.contains('all-clear')){
112 | resetCalculator()
113 | return
114 | }
115 |
116 | if(target.classList.contains('equal-sign')){
117 | handleEqual()
118 | return
119 | }
120 |
121 | inputDigit(target.value)
122 |
123 | })
--------------------------------------------------------------------------------
/quiz-app/script.js:
--------------------------------------------------------------------------------
1 | // array pertanyaan dan jawaban
2 | const questions = [
3 | {
4 | question: "What is the capital of France?",
5 | answers: [
6 | { text: "Paris", correct: true },
7 | { text: "London", correct: false },
8 | { text: "Rome", correct: false },
9 | { text: "Berlin", correct: false }
10 | ]
11 | },
12 | {
13 | question: "Who wrote 'To Kill a Mockingbird'?",
14 | answers: [
15 | { text: "Harper Lee", correct: true },
16 | { text: "Mark Twain", correct: false },
17 | { text: "Ernest Hemingway", correct: false },
18 | { text: "F. Scott Fitzgerald", correct: false }
19 | ]
20 | },
21 | {
22 | question: "What is the largest planet in our solar system?",
23 | answers: [
24 | { text: "Jupiter", correct: true },
25 | { text: "Saturn", correct: false },
26 | { text: "Earth", correct: false },
27 | { text: "Mars", correct: false }
28 | ]
29 | },
30 | {
31 | question: "Which language is primarily used for web development?",
32 | answers: [
33 | { text: "JavaScript", correct: true },
34 | { text: "Python", correct: false },
35 | { text: "C++", correct: false },
36 | { text: "Java", correct: false }
37 | ]
38 | }
39 | ];
40 |
41 | let currentQuestionIndex = 0
42 | let score = 0
43 |
44 | // ambil semua element yang kita butuhkan dari "ID"
45 | const questionContainer = document.getElementById("question-container")
46 | const questionElement = document.getElementById("question")
47 | const answerButtons = document.getElementById("answer-buttons")
48 | const nextButton = document.getElementById("next-btn")
49 | const resultContainer = document.getElementById("result-container")
50 | const scoreElement = document.getElementById("score")
51 | const restartButton = document.getElementById("restart-btn")
52 |
53 | // buat fungsi untuk memulai quiz
54 | function startQuiz(){
55 | currentQuestionIndex = 0
56 | score = 0
57 | nextButton.style.display = 'none'
58 | resultContainer.style.display = 'none'
59 | questionContainer.style.display = 'block'
60 |
61 | //function untuk menampilkan question
62 | showQuestion()
63 | }
64 |
65 | function showQuestion(){
66 | // untuk mereset state
67 | resetState()
68 |
69 | const currentQuestion = questions[currentQuestionIndex]
70 | questionElement.textContent = currentQuestion.question
71 |
72 | // buat button untuk jawaban secara dinamis
73 | currentQuestion.answers.forEach(answer => {
74 | const button = document.createElement('button')
75 | button.textContent = answer.text
76 | button.classList.add('answer-btn')
77 | if(answer.correct){
78 | button.dataset.correct = answer.correct
79 | }
80 | button.addEventListener('click', selectAnswer)
81 | answerButtons.appendChild(button)
82 | })
83 | }
84 |
85 | function resetState(){
86 | nextButton.style.display = 'none'
87 | while(answerButtons.firstChild){
88 | answerButtons.removeChild(answerButtons.firstChild)
89 | }
90 | }
91 |
92 | function selectAnswer(e) {
93 | const selectedButton = e.target
94 | const correct = selectedButton.dataset.correct === 'true'
95 | if(correct) {
96 | score++
97 | selectedButton.style.backgroundColor = '#4caf50'
98 | } else{
99 | selectedButton.style.backgroundColor = '#f44336'
100 | }
101 | //disable all button after select answer
102 | Array.from(answerButtons.children).forEach(button => {
103 | button.disabled = true
104 | if(button.dataset.correct){
105 | button.style.backgroundColor = '#4caf50'
106 | }
107 | })
108 |
109 | // tampilkan next button jika pertanyaan masih ada
110 | if(currentQuestionIndex < questions.length - 1){
111 | nextButton.style.display = 'inline-block'
112 | } else{
113 | showResult()
114 | }
115 | }
116 |
117 | // handle event listener nextbtn
118 |
119 | nextButton.addEventListener('click', () => {
120 | currentQuestionIndex++
121 | showQuestion()
122 | })
123 |
124 | function showResult(){
125 | questionContainer.style.display = 'none'
126 | resultContainer.style.display = 'block'
127 | scoreElement.textContent = `Your score : ${score} / ${questions.length}`
128 | }
129 |
130 | restartButton.addEventListener('click', startQuiz)
131 |
132 |
133 |
134 |
135 |
136 | startQuiz()
--------------------------------------------------------------------------------
/shopping-cart/main.js:
--------------------------------------------------------------------------------
1 | class Product{
2 | constructor(id,name,description, price, image){
3 | this.id = id
4 | this.name = name
5 | this.description = description
6 | this.price = price
7 | this.image = image
8 | }
9 |
10 | displayCard(){
11 | return `
12 |
13 | ${this.name}
14 | $${this.price.toFixed(2)}
15 | Quantity in cart: 0
16 |
17 |
18 |
19 | `
20 | }
21 | }
22 |
23 | class CartItem{
24 | constructor(product, quantity =1){
25 | this.product = product
26 | this.quantity = quantity
27 | }
28 | incrementQuantity(){
29 | this.quantity ++
30 | }
31 | getTotalPrice(){
32 | return this.quantity * this.product.price
33 | }
34 | }
35 |
36 | class ShoppingCart{
37 | constructor(){
38 | this.products = []
39 | this.cart = []
40 | }
41 | addProduct(product){
42 | this.products.push(product)
43 | }
44 | displayProducts(){
45 | const productList = document.getElementById('product-list')
46 | productList.innerHTML = ''
47 | this.products.forEach(product => {
48 | const productCard = document.createElement('div')
49 | productCard.classList.add('product-card')
50 | productCard.innerHTML = product.displayCard()
51 | productList.appendChild(productCard)
52 | })
53 | }
54 |
55 | viewProductDetail(id){
56 | const product = this.products.find(p => p.id === id)
57 | document.getElementById('detail-image').src = product.image
58 | document.getElementById('detail-title').textContent = product.name
59 | document.getElementById('detail-description').textContent = product.description
60 |
61 | document.getElementById('detail-price').textContent = `$${product.price.toFixed(2)}`
62 |
63 | document.getElementById('add-to-cart-btn').setAttribute('onclick', `shoppingCart.addToCart(${product.id})`)
64 |
65 | this.toggleProductDetail()
66 | }
67 |
68 | toggleProductDetail(addFromDisplay = false){
69 | const modal = document.getElementById('product-modal')
70 | modal.style.display = modal.style.display === 'block'? 'none' : "block"
71 | }
72 |
73 | addToCart(id){
74 | const product = this.products.find(p=> p.id === id)
75 | const existingItem = this.cart.find(item => item.product.id === id)
76 |
77 | if (existingItem){
78 | existingItem.incrementQuantity()
79 | } else {
80 | this.cart.push(new CartItem(product))
81 | }
82 |
83 | this.updateCart()
84 | this.updateProductQuantity(id)
85 | }
86 |
87 | updateCart(){
88 | const cartItems = document.getElementById('cart-items')
89 | cartItems.innerHTML = ''
90 | let totalPrice = 0
91 |
92 | this.cart.forEach((item,index)=> {
93 | const itemTotalPrice = item.getTotalPrice()
94 | totalPrice += itemTotalPrice
95 |
96 | const li = document.createElement('li')
97 |
98 | li.innerHTML = `
99 | ${item.product.name} - $${item.product.price.toFixed(2)} x ${item.quantity} = $${itemTotalPrice.toFixed(2)}
100 |
101 | `
102 | cartItems.appendChild(li)
103 | })
104 |
105 | document.getElementById('cart-count').textContent = this.cart.reduce((sum,item) => sum + item.quantity,0)
106 | document.getElementById('total-price').textContent = totalPrice.toFixed(2)
107 | }
108 |
109 | updateProductQuantity(id){
110 | const cartItem = this.cart.find(item => item.product.id === id)
111 | const quantityElement = document.getElementById(`quantity-${id}`)
112 |
113 |
114 | if(cartItem) {
115 | quantityElement.textContent = `Quantity in cart: ${cartItem.quantity}`
116 | } else {
117 | quantityElement.textContent = `Quantity in cart: 0`
118 | }
119 | }
120 |
121 | removeFromCart(index){
122 | const removedItem = this.cart.splice(index,1)[0]
123 | this.updateCart()
124 | this.updateProductQuantity(removedItem.product.id)
125 | }
126 |
127 | toggleCart(){
128 | const modal = document.getElementById('cart-modal')
129 | modal.style.display = modal.style.display === 'block' ? 'none': 'block'
130 | }
131 | }
132 |
133 | // inisialisasi shopping cart dan product
134 | const shoppingCart = new ShoppingCart()
135 |
136 | shoppingCart.addProduct(
137 | new Product(
138 | 1,
139 | 'Product 1',
140 | 'This is the description for Product 1',
141 | 10.0,
142 | 'https://images.unsplash.com/photo-1633455583769-4d8c28b50286?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDJ8fHxlbnwwfHx8fHw%3D'
143 | )
144 | );
145 | shoppingCart.addProduct(
146 | new Product(
147 | 2,
148 | 'Product 2',
149 | 'This is the description for Product 2',
150 | 20.0,
151 | 'https://images.unsplash.com/photo-1613140506142-277c6241b858?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
152 | )
153 | );
154 | shoppingCart.addProduct(
155 | new Product(
156 | 3,
157 | 'Product 3',
158 | 'This is the description for Product 3',
159 | 30.0,
160 | 'https://images.unsplash.com/photo-1520170350707-b2da59970118?q=80&w=1965&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'
161 | )
162 | );
163 |
164 | shoppingCart.displayProducts()
165 |
166 | window.onclick = function(event) {
167 | const cartModal = document.getElementById('cart-modal')
168 | const productModal = document.getElementById('product-modal')
169 |
170 | if(event.target == cartModal){
171 | cartModal.style.display = "none"
172 | }
173 | if(event.target == productModal){
174 | productModal.style.display = "none"
175 | }
176 | }
177 |
--------------------------------------------------------------------------------