├── Beat-It ├── index.html ├── index.js ├── script.js ├── sounds │ ├── bubbles.mp3 │ ├── clay.mp3 │ ├── confetti.mp3 │ ├── glimmer.mp3 │ ├── moon.mp3 │ └── ufo.mp3 └── style.css ├── DOM-Array-Methods ├── index.html ├── script.js └── style.css ├── Exchange-Rate-Calculator ├── index.html ├── money.png ├── script.js └── style.css ├── Expense-Tracker ├── index.html ├── script.js └── style.css ├── GitHub-Profile-Finder ├── images.png ├── index.html ├── script.js └── style.css ├── Hangman-Game ├── index.html ├── script.js └── style.css ├── Meditate-App ├── bg12.jpg ├── index.html ├── script.js ├── style.css └── y2mate.com - 15 Minute Super Deep Meditation Music_ Relax Mind Body, Inner Peace, Relaxing Music, ☯2563B.mp3 ├── Modal-Menu ├── index.html ├── script.js └── style.css ├── Movie-Info ├── index.html ├── script.js └── style.css ├── Movie-Seat-Booking ├── index.html ├── script.js └── style.css ├── Music-Player ├── images │ ├── hey.jpg │ ├── summer.jpg │ └── ukulele.jpg ├── index.html ├── music │ ├── hey.mp3 │ ├── summer.mp3 │ └── ukulele.mp3 ├── script.js └── style.css ├── New-Year-Countdown ├── README.md ├── index.html ├── loaderx.gif ├── script.js └── style.css ├── OG-Video-Player ├── index.html ├── noise12.png ├── poster.jpg ├── progress.css ├── script.js └── style.css ├── README.md ├── Recipe-App ├── index.html ├── script.js └── style.css └── Todo ├── index.html ├── script.js └── style.css /Beat-It/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | Beat It ⚡ 13 | 14 | 15 |
16 |
17 |

Beat It ⚡

18 |

Sound goes brr

19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 31 |
32 |
33 | 36 |
37 |
38 | 41 |
42 |
43 | 46 |
47 |
48 | 51 |
52 |
53 |
54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Beat-It/index.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", () => { 2 | const sounds = document.querySelectorAll(".sound"); 3 | const pads = document.querySelectorAll(".pads div"); 4 | const visual = document.querySelector(".visual"); 5 | const colors = [ 6 | "#60d394", 7 | "#d36060", 8 | "#c060d3", 9 | "#d3d160", 10 | "#606bd3", 11 | "#60c2d3" 12 | ]; 13 | 14 | pads.forEach((pad, index) => { 15 | pad.addEventListener("click", function() { 16 | sounds[index].currentTime = 0; 17 | sounds[index].play(); 18 | createBubble(index); 19 | }); 20 | }); 21 | 22 | const createBubble = index => { 23 | //Create bubbles 24 | const bubble = document.createElement("div"); 25 | visual.appendChild(bubble); 26 | bubble.style.backgroundColor = colors[index]; 27 | bubble.style.animation = `jump 1s ease`; 28 | bubble.addEventListener("animationend", function() { 29 | visual.removeChild(this); 30 | }); 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /Beat-It/script.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", () => { 2 | const sounds = document.querySelectorAll(".sound"); 3 | const pads = document.querySelectorAll(".pads div"); 4 | const visual = document.querySelector(".visual"); 5 | const colors = [ 6 | "#60d394", 7 | "#d36060", 8 | "#c060d3", 9 | "#d3d160", 10 | "#606bd3", 11 | "#60c2d3" 12 | ]; 13 | 14 | pads.forEach((pad, index) => { 15 | pad.addEventListener("click", function() { 16 | sounds[index].currentTime = 0; 17 | sounds[index].play(); 18 | createBubble(index); 19 | }); 20 | }); 21 | 22 | const createBubble = index => { 23 | // squares/bubbles 24 | const bubble = document.createElement("div"); 25 | visual.appendChild(bubble); 26 | bubble.style.backgroundColor = colors[index]; 27 | bubble.style.animation = `jump 1s ease`; 28 | bubble.addEventListener("animationend", function() { 29 | visual.removeChild(this); 30 | }); 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /Beat-It/sounds/bubbles.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/bubbles.mp3 -------------------------------------------------------------------------------- /Beat-It/sounds/clay.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/clay.mp3 -------------------------------------------------------------------------------- /Beat-It/sounds/confetti.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/confetti.mp3 -------------------------------------------------------------------------------- /Beat-It/sounds/glimmer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/glimmer.mp3 -------------------------------------------------------------------------------- /Beat-It/sounds/moon.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/moon.mp3 -------------------------------------------------------------------------------- /Beat-It/sounds/ufo.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Beat-It/sounds/ufo.mp3 -------------------------------------------------------------------------------- /Beat-It/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | font-family: 'Poppins', 11 | sans-serif; 12 | background-color: rgb(253, 255, 253); 13 | } 14 | 15 | .app { 16 | min-height: 100vh; 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: space-between; 20 | align-items: center; 21 | } 22 | 23 | header h1 { 24 | margin: 50px 0px 30px 0px; 25 | text-shadow: 2px 2px #8ae0c4; 26 | text-align: center; 27 | color: rgb(37, 90, 94); 28 | font-size: 70px; 29 | } 30 | header p { 31 | font-size: 35px; 32 | margin-right: 2rem; 33 | font-weight: bold; 34 | color: rgb(49, 104, 126); 35 | text-shadow: 2px 2px #91e6c9; 36 | } 37 | 38 | .pads { 39 | background: lightblue; 40 | width: 100%; 41 | display: flex; 42 | } 43 | .pads > div { 44 | height: 100px; 45 | width: 100px; 46 | cursor: pointer; 47 | border: 4px solid rgb(59, 58, 58); 48 | flex: 1; 49 | } 50 | .pad1 { 51 | background: #59d491; 52 | } 53 | .pad2 { 54 | background: #d13c3c; 55 | } 56 | .pad3 { 57 | background: #c059d4; 58 | } 59 | .pad4 { 60 | background: #e6e36a; 61 | } 62 | .pad5 { 63 | background: #6a75db; 64 | } 65 | .pad6 { 66 | background: #6ec1cf; 67 | } 68 | 69 | .visual > div { 70 | position: absolute; 71 | bottom: 0%; 72 | height: 50px; 73 | width: 50px; 74 | border-radius: 20%; 75 | transform: scale(1); 76 | z-index: -1; 77 | } 78 | 79 | 80 | 81 | 82 | @keyframes jump { 83 | 0% { 84 | bottom: 0%; 85 | transform: perspective(80%); 86 | left: 20%; 87 | } 88 | 50% { 89 | bottom: 50%; 90 | left: 50%; 91 | } 92 | 93 | 100% { 94 | bottom: 00%; 95 | left: 80%; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /DOM-Array-Methods/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | DOM Array Methods 11 | 12 | 13 | 14 |

DOM Array Methods

15 | 16 |
17 | 24 | 25 |
26 |

Person Wealth

27 |
28 |
29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DOM-Array-Methods/script.js: -------------------------------------------------------------------------------- 1 | const main = document.getElementById('main'); 2 | const addUserBtn = document.getElementById('add-user'); 3 | const doubleBtn = document.getElementById('double'); 4 | const showMillionairesBtn = document.getElementById('show-millionaires'); 5 | const sortBtn = document.getElementById('sort'); 6 | const calculateWealthBtn = document.getElementById('calculate-wealth'); 7 | 8 | 9 | let data = [] 10 | 11 | getRandomUser() 12 | getRandomUser() 13 | getRandomUser() 14 | getRandomUser() 15 | 16 | 17 | 18 | //fetching the API and adding money 19 | 20 | async function getRandomUser(){ 21 | 22 | const res = await fetch("https://randomuser.me/api") 23 | 24 | const data = await res.json() 25 | 26 | 27 | 28 | const user = data.results[0] 29 | 30 | const newUser = { 31 | name : `${user.name.first} ${user.name.last}`, 32 | money: Math.floor(Math.random()*1000000) 33 | } 34 | 35 | addData(newUser) 36 | } 37 | 38 | let calculateWealth = () =>{ 39 | const wealth = data.reduce((acc, user) => (acc += user.money), 0); 40 | 41 | const wealthElement = document.createElement('div'); 42 | wealthElement.innerHTML = `

Total Wealth: ${formatMoney( 43 | wealth 44 | )}

`; 45 | main.appendChild(wealthElement); 46 | } 47 | 48 | 49 | let showMillionaires= () =>{ 50 | data = data.filter(user => user.money >= 1000000); 51 | 52 | updateDOM(); 53 | } 54 | 55 | 56 | 57 | 58 | let sortRichest = () => { 59 | data.sort((a,b) => b.money - a.money) 60 | updateDOM() 61 | } 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | let doubleMoney = () =>{ 70 | 71 | data= data.map((user)=>{ 72 | return { ...user, money: user.money*2} 73 | }) 74 | 75 | updateDOM() 76 | } 77 | 78 | // add new obj to data array 79 | 80 | let addData = (obj) => { 81 | 82 | data.push(obj) 83 | 84 | updateDOM() 85 | } 86 | 87 | 88 | 89 | let updateDOM = ( providedData = data ) =>{ 90 | 91 | // clear the main div 92 | 93 | main.innerHTML = `

Person Wealth

` 94 | 95 | providedData.forEach( item => { 96 | 97 | const element = document.createElement('div') // literally creating an HTML element 98 | 99 | element.classList.add('person') //adding "person" as a class onto this 100 | 101 | element.innerHTML = ` ${item.name} 102 | ${formatMoney(item.money)}` 103 | 104 | main.appendChild(element) 105 | }) 106 | 107 | } 108 | 109 | 110 | 111 | // format no. as money 112 | 113 | let formatMoney = ( number ) =>'$' + number.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'); 114 | 115 | 116 | // event listeners 117 | 118 | addUserBtn.addEventListener("click", getRandomUser) 119 | 120 | doubleBtn.addEventListener("click", doubleMoney) 121 | 122 | sortBtn.addEventListener("click", sortRichest) 123 | 124 | showMillionairesBtn.addEventListener("click", showMillionaires) 125 | 126 | calculateWealthBtn.addEventListener("click", calculateWealth) 127 | -------------------------------------------------------------------------------- /DOM-Array-Methods/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | font-family: "Noto Sans", sans-serif; 6 | } 7 | 8 | body { 9 | background-color: rgb(247, 230, 223); 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | min-height: 100vh; 14 | margin: 0; 15 | } 16 | 17 | .container { 18 | display: flex; 19 | padding: 20px; 20 | margin: 0 auto; 21 | max-width: 100%; 22 | width: 800px; 23 | } 24 | 25 | aside { 26 | padding: 10px 20px; 27 | width: 250px; 28 | border-right: 1px solid #111; 29 | } 30 | 31 | button { 32 | background-color: whitesmoke; 33 | border: solid 1px #111; 34 | cursor: pointer; 35 | border-radius: 7px; 36 | display: block; 37 | width: 100%; 38 | padding: 10px; 39 | margin-bottom: 2rem; 40 | font-weight: bold; 41 | font-size: 14px; 42 | } 43 | 44 | button:hover { 45 | background-color: #111; 46 | color: whitesmoke; 47 | } 48 | 49 | main { 50 | flex: 1; 51 | padding: 10px 20px; 52 | } 53 | 54 | h2 { 55 | border-bottom: 1px solid #111; 56 | padding-bottom: 10px; 57 | display: flex; 58 | justify-content: space-between; 59 | font-weight: 400; 60 | margin: 0 0 20px; 61 | } 62 | 63 | h3 { 64 | border-bottom: 1px solid #111; 65 | padding: 10px; 66 | display: flex; 67 | background-color: whitesmoke; 68 | justify-content: space-between; 69 | font-weight: 400; 70 | margin: 20 0 0px; 71 | } 72 | 73 | .person { 74 | display: flex; 75 | justify-content: space-between; 76 | font-size: 20px; 77 | margin-bottom: 10px; 78 | } 79 | 80 | h1 { 81 | margin-top: 2em; 82 | } 83 | -------------------------------------------------------------------------------- /Exchange-Rate-Calculator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Exchange Rate Calculator 9 | 10 | 11 | 12 | 13 | 14 |

Exchange Rate Calculator

15 |

Choose the currency and the amounts to get the exchange rate

16 | 17 |
18 |
19 | 73 | 74 |
75 | 76 |
77 | 80 |
81 |
82 | 83 |
84 | 138 | 139 |
140 |
141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /Exchange-Rate-Calculator/money.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Exchange-Rate-Calculator/money.png -------------------------------------------------------------------------------- /Exchange-Rate-Calculator/script.js: -------------------------------------------------------------------------------- 1 | const currencyElement_one = document.getElementById('currency-one') 2 | 3 | const currencyElement_two = document.getElementById('currency-two') 4 | 5 | 6 | const amountElement_one = document.getElementById('amount-one') 7 | 8 | const amountElement_two = document.getElementById('amount-two') 9 | 10 | const rateElement = document.getElementById('rate') 11 | 12 | const swap = document.getElementById('swap') 13 | 14 | 15 | // fetch exchange rates + DOM updates 16 | 17 | const calculate = (()=>{ 18 | 19 | const currency_one = currencyElement_one.value 20 | const currency_two = currencyElement_two.value 21 | 22 | fetch(`https://api.exchangerate-api.com/v4/latest/${currency_one}`) 23 | .then(res=> res.json()) 24 | .then(data => { 25 | 26 | 27 | const rate = data.rates[currency_two]; //providing the index for the rate 28 | 29 | rateElement.innerText = `1 ${currency_one} = ${rate} ${currency_two}` 30 | 31 | amountElement_two.value = (amountElement_one.value * rate).toFixed(2) //2 deciaml pts 32 | 33 | 34 | 35 | 36 | 37 | }) 38 | }) 39 | 40 | 41 | 42 | // event listeners 43 | 44 | currencyElement_one.addEventListener("change", calculate) 45 | 46 | amountElement_one.addEventListener("input", calculate) 47 | 48 | currencyElement_two.addEventListener("change", calculate) 49 | 50 | amountElement_one.addEventListener("input", calculate) 51 | 52 | swap.addEventListener('click', ()=>{ 53 | const temp = currencyElement_one.value 54 | currencyElement_one.value = currencyElement_two.value 55 | currencyElement_two.value = temp 56 | calculate() 57 | 58 | }) 59 | calculate() 60 | -------------------------------------------------------------------------------- /Exchange-Rate-Calculator/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Mukta&display=swap"); 2 | 3 | :root { 4 | --primary-color: rgb(25, 85, 85); 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | font-family: "Mukta", sans-serif; 10 | } 11 | 12 | body { 13 | background-color: whitesmoke; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | height: 100vh; 19 | margin: 0; 20 | padding: 20px; 21 | } 22 | 23 | h1 { 24 | color: var(--primary-color); 25 | } 26 | 27 | p { 28 | text-align: center; 29 | font-size: 21px; 30 | color: var(--primary-color); 31 | } 32 | 33 | .btn { 34 | color: wheat; 35 | background: var(--primary-color); 36 | cursor: pointer; 37 | border-radius: 5px; 38 | font-size: 13px; 39 | padding: 5px 12px; 40 | } 41 | 42 | .money-img { 43 | width: 240px; 44 | } 45 | 46 | .currency { 47 | padding: 40px 0; 48 | display: flex; 49 | align-items: center; 50 | justify-content: space-between; 51 | } 52 | 53 | .currency select { 54 | padding: 10px 20px 10px 10px; 55 | border: 1px solid #f1e7e7; 56 | font-size: 16px; 57 | background: transparent; 58 | appearance: none; 59 | background-position: right 10px top 50%, 0, 0; 60 | background-size: 12px auto, 100%; 61 | background-repeat: no-repeat; 62 | background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%20000002%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E"); 63 | } 64 | 65 | .currency input { 66 | border: none; 67 | background: transparent; 68 | font-size: 32px; 69 | text-align: right; 70 | } 71 | 72 | .swap-rate-container { 73 | display: flex; 74 | align-items: center; 75 | justify-content: space-between; 76 | } 77 | 78 | .rate { 79 | color: var(--primary-color); 80 | font-size: 14px; 81 | padding: 0 10px; 82 | } 83 | select:focus, 84 | input:focus, 85 | button:focus { 86 | outline: 0; 87 | } 88 | 89 | @media (max-width: 600px) { 90 | .currency input { 91 | width: 200px; 92 | } 93 | .money-img { 94 | height: 140px; 95 | width: 140px; 96 | margin-top: 1rem; 97 | align-items: center; 98 | } 99 | h1 { 100 | font-size: 26px; 101 | } 102 | 103 | p { 104 | font-size: 15px; 105 | font-weight: 100; 106 | color: var(--primary-color); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Expense-Tracker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Expense Tracker 9 | 10 | 11 |

Expense Tracker

12 | 13 |
14 |

Your Balance

15 |

$0.00

16 | 17 |
18 |
19 |

Income

20 |

+$0.00

21 |
22 |
23 |

Expense

24 |

-$0.00

25 |
26 |
27 | 28 |

History

29 | 32 | 33 |

Add new transaction

34 |
35 |
36 | 37 | 38 |
39 |
40 | 44 | 45 |
46 | 47 |
48 |
49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Expense-Tracker/script.js: -------------------------------------------------------------------------------- 1 | const balance = document.getElementById('balance'); 2 | const money_plus = document.getElementById('money-plus'); 3 | const money_minus = document.getElementById('money-minus'); 4 | const list = document.getElementById('list'); 5 | const form = document.getElementById('form'); 6 | const text = document.getElementById('text'); 7 | const amount = document.getElementById('amount'); 8 | 9 | 10 | 11 | const localStorageTransactions = JSON.parse( 12 | localStorage.getItem('transactions') 13 | ); 14 | 15 | let transactions = 16 | localStorage.getItem('transactions') !== null ? localStorageTransactions : []; 17 | 18 | // add transaction 19 | let addTransaction = (e) => { 20 | e.preventDefault(); 21 | 22 | if (text.value.trim() === '' || amount.value.trim() === '') { 23 | alert('Please add a text and amount'); 24 | } else { 25 | const transaction = { 26 | id: generateID(), 27 | text: text.value, 28 | amount: +amount.value 29 | }; 30 | 31 | transactions.push(transaction); 32 | 33 | addTransactionDOM(transaction); 34 | 35 | updateValues(); 36 | 37 | updateLocalStorage(); 38 | 39 | text.value = ''; 40 | amount.value = ''; 41 | } 42 | } 43 | 44 | // generate random ID 45 | let generateID = () => { 46 | return Math.floor(Math.random() * 100000000); 47 | } 48 | 49 | // add transactions to DOM list 50 | function addTransactionDOM(transaction) { 51 | 52 | // get sign 53 | const sign = transaction.amount < 0 ? '-' : '+'; 54 | 55 | const item = document.createElement('li'); 56 | 57 | // add class based on value 58 | item.classList.add(transaction.amount < 0 ? 'minus' : 'plus'); 59 | 60 | item.innerHTML = ` 61 | ${transaction.text} ${sign}${Math.abs( 62 | transaction.amount 63 | )} 66 | `; 67 | 68 | list.appendChild(item); 69 | } 70 | 71 | // Update the balance, income and expense 72 | let updateValues = () => { 73 | const amounts = transactions.map(transaction => transaction.amount); 74 | 75 | const total = amounts.reduce((acc, item) => (acc += item), 0).toFixed(2); 76 | 77 | const income = amounts 78 | .filter(item => item > 0) 79 | .reduce((acc, item) => (acc += item), 0) 80 | .toFixed(2); 81 | 82 | const expense = ( 83 | amounts.filter(item => item < 0).reduce((acc, item) => (acc += item), 0) * 84 | -1 85 | ).toFixed(2); 86 | 87 | balance.innerText = `$${total}`; 88 | money_plus.innerText = `$${income}`; 89 | money_minus.innerText = `$${expense}`; 90 | } 91 | 92 | // remove transaction by ID 93 | function removeTransaction(id) { 94 | transactions = transactions.filter(transaction => transaction.id !== id); 95 | 96 | updateLocalStorage(); 97 | 98 | init(); 99 | } 100 | 101 | // Update local storage transactions 102 | function updateLocalStorage() { 103 | localStorage.setItem('transactions', JSON.stringify(transactions)); 104 | } 105 | 106 | // Init app 107 | let init = () => { 108 | list.innerHTML = ''; 109 | 110 | transactions.forEach(addTransactionDOM); 111 | updateValues(); 112 | } 113 | 114 | init(); 115 | 116 | form.addEventListener('submit', addTransaction); 117 | -------------------------------------------------------------------------------- /Expense-Tracker/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap'); 2 | 3 | *{ 4 | font-family: 'Noto Sans', 5 | sans-serif; 6 | margin: 0; 7 | box-sizing: border-box; 8 | } 9 | 10 | 11 | :root{ 12 | --box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 13 | 0 1px 2px rgba(0, 0, 0, 0.24) 14 | } 15 | 16 | body { 17 | background-color: #f3faf9; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | min-height: 100vh; 23 | } 24 | 25 | .container { 26 | margin: 30px auto; 27 | width: 350px; 28 | } 29 | 30 | h1 { 31 | letter-spacing: 1px; 32 | text-align: center; 33 | 34 | } 35 | 36 | h2{ 37 | margin-top: 2.9rem; 38 | font-size: 2.5rem; 39 | color: rgb(216, 59, 59); 40 | letter-spacing: 2px; 41 | text-shadow: 1px 1.2px #ec47d6; 42 | } 43 | h3 { 44 | border-bottom: 1px solid #bbb; 45 | padding-bottom: 10px; 46 | margin: 40px 0 10px; 47 | text-align: center; 48 | } 49 | 50 | h4 { 51 | margin: 0; 52 | text-align: center; 53 | text-transform: uppercase; 54 | } 55 | 56 | .inc-exp-container { 57 | background-color: #fff; 58 | border-radius: 71px; 59 | background: #fcfffe; 60 | box-shadow: 0px 6px 10px #b1fafa, 61 | 917px -87px 54px #fff7f7; 62 | /* box-shadow: var(--box-shadow); */ 63 | padding: 20px; 64 | display: flex; 65 | justify-content: space-between; 66 | margin: 20px 0; 67 | } 68 | 69 | .inc-exp-container>div { 70 | flex: 1; 71 | text-align: center; 72 | } 73 | 74 | .inc-exp-container>div:first-of-type { 75 | border-right: 1px solid #dedede; 76 | 77 | } 78 | 79 | .money { 80 | font-size: 20px; 81 | letter-spacing: 1px; 82 | margin: 5px 0; 83 | 84 | 85 | } 86 | 87 | .money.plus { 88 | color: #4fbd7d; 89 | } 90 | 91 | .money.minus { 92 | color: #e05141; 93 | } 94 | 95 | label { 96 | display: inline-block; 97 | margin: 10px 0; 98 | } 99 | 100 | .form-control{ 101 | margin-bottom: 2.9rem; 102 | } 103 | input[type='text'], 104 | input[type='number'] { 105 | border: 1px solid #dedede; 106 | display: block; 107 | font-size: 16px; 108 | padding: 11px; 109 | width: 100%; 110 | border-radius: 71px; 111 | box-shadow: 4px 6px 7px 0px rgba(131, 190, 173, 0.7); 112 | } 113 | 114 | #text, #amount:focus{ 115 | outline: none; 116 | } 117 | 118 | .btn { 119 | cursor: pointer; 120 | background-color: #4d3c91; 121 | box-shadow: var(--box-shadow); 122 | color: #fff; 123 | border: 0; 124 | display: block; 125 | border-radius: 4px; 126 | font-size: 16px; 127 | margin: 10px 0 30px; 128 | padding: 10px; 129 | width: 100%; 130 | } 131 | 132 | .btn:hover{ 133 | background-color: #469b69; 134 | 135 | } 136 | 137 | .btn:focus, 138 | .delete-btn:focus { 139 | outline: 0; 140 | } 141 | 142 | .list { 143 | list-style-type: none; 144 | padding: 0; 145 | margin-bottom: 40px; 146 | } 147 | 148 | .list li { 149 | background-color: #fff; 150 | box-shadow: var(--box-shadow); 151 | color: #333; 152 | display: flex; 153 | justify-content: space-between; 154 | position: relative; 155 | padding: 10px; 156 | margin: 10px 0; 157 | } 158 | 159 | .list li.plus { 160 | border-right: 5px solid #2ecc71; 161 | } 162 | 163 | .list li.minus { 164 | border-right: 5px solid #c0392b; 165 | } 166 | 167 | .delete-btn { 168 | cursor: pointer; 169 | background-color: #e74c3c; 170 | border: 0; 171 | color: #fff; 172 | font-size: 20px; 173 | line-height: 20px; 174 | padding: 2px 5px; 175 | position: absolute; 176 | top: 50%; 177 | left: 0; 178 | transform: translate(-100%, -50%); 179 | opacity: 0; 180 | transition: opacity 0.3s ease; 181 | } 182 | 183 | .list li:hover .delete-btn { 184 | opacity: 1; 185 | } 186 | -------------------------------------------------------------------------------- /GitHub-Profile-Finder/images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/GitHub-Profile-Finder/images.png -------------------------------------------------------------------------------- /GitHub-Profile-Finder/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Github Profile Finder 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /GitHub-Profile-Finder/script.js: -------------------------------------------------------------------------------- 1 | const APIURL = "https://api.github.com/users/"; 2 | 3 | const main = document.getElementById("main"); 4 | const form = document.getElementById("form"); 5 | const search = document.getElementById("search"); 6 | 7 | getUser("proghead00"); 8 | 9 | async function getUser(username) { 10 | const resp = await fetch(APIURL + username); 11 | const respData = await resp.json(); 12 | 13 | createUserCard(respData); 14 | 15 | getRepos(username); 16 | } 17 | 18 | async function getRepos(username) { 19 | const resp = await fetch(APIURL + username + "/repos"); 20 | const respData = await resp.json(); 21 | 22 | addReposToCard(respData); 23 | } 24 | 25 | let createUserCard = (user) => { 26 | const cardHTML = ` 27 |
28 |
29 | ${user.name} 30 | 31 | 32 |
33 |
34 | 35 |
36 |

${user.name}

37 | 38 | 39 | 40 | 41 | 42 | 43 | redirect 46 | 47 | 48 | 49 | 50 | 51 |
52 |

${user.bio}

53 | 54 | 59 | 60 |
61 |
62 |

GitHub Statistics

63 | 64 | 65 | 66 | 67 |
68 | `; 69 | 70 | main.innerHTML = cardHTML; 71 | } 72 | 73 | function addReposToCard(repos) { 74 | const reposEl = document.getElementById("repos"); 75 | 76 | repos 77 | .sort((a, b) => b.stargazers_count - a.stargazers_count) 78 | .slice(0, 10) 79 | .forEach((repo) => { 80 | const repoEl = document.createElement("a"); 81 | repoEl.classList.add("repo"); 82 | 83 | repoEl.href = repo.html_url; 84 | repoEl.target = "_blank"; 85 | repoEl.innerText = repo.name; 86 | 87 | reposEl.appendChild(repoEl); 88 | }); 89 | } 90 | 91 | form.addEventListener("submit", (e) => { 92 | e.preventDefault(); 93 | 94 | const user = search.value; 95 | 96 | if (user) { 97 | getUser(user); 98 | 99 | search.value = ""; 100 | } 101 | }); 102 | -------------------------------------------------------------------------------- /GitHub-Profile-Finder/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Raleway:wght@500&display=swap'); 2 | @import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap'); 3 | *{ 4 | box-sizing: border-box; 5 | } 6 | 7 | body{ 8 | 9 | background-image: linear-gradient(12deg, #3e2da3 0%, #41073f 84%); 10 | font-family: 'Raleway',sans-serif; 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | justify-content: center; 15 | 16 | margin: 0; 17 | min-height: 100vh; 18 | } 19 | 20 | 21 | input { 22 | background-color: #7841a5; 23 | border-radius: 14px; 24 | 25 | 26 | border: none; 27 | box-shadow: 0 -13px 10px rgba(154, 160, 185, 0.05), 28 | 0 15px 40px rgba(0, 0, 0, 0.3); 29 | color: white; 30 | font-size: 1rem; 31 | padding: 1em; 32 | margin-bottom: 2rem; 33 | } 34 | 35 | input::placeholder { 36 | color: #bbb; 37 | font-family: 'Raleway', 38 | sans-serif; 39 | text-align: center; 40 | } 41 | 42 | input:focus { 43 | outline: none; 44 | } 45 | 46 | .card { 47 | 48 | 49 | background-image: linear-gradient(315deg, #482681 10%, #436096 100%); 50 | border-radius: 20px; 51 | 52 | box-shadow: 5px 8px 15px 3px rgb(22, 21, 94); 53 | display: flex; 54 | padding: 3rem; 55 | max-width: 800px; 56 | } 57 | .det{ 58 | display: flex; 59 | } 60 | 61 | .redirect{ 62 | margin-top: 1.7em; 63 | margin-left: 1em; 64 | height:25px; 65 | width:25px; 66 | display: flex; 67 | } 68 | 69 | .redirect:hover{ 70 | transform: scale(1.2); 71 | } 72 | 73 | .avatar { 74 | border: 10px solid #3b68a1; 75 | box-shadow: 1px 2px 22px 1px rgb(22, 21, 73,.9); 76 | border-radius: 50%; 77 | height: 150px; 78 | width: 150px; 79 | } 80 | 81 | .user-info { 82 | color: #eee; 83 | 84 | margin-left: 2rem; 85 | } 86 | 87 | .user-info h2 { 88 | margin-top: 0; 89 | } 90 | 91 | .user-info ul { 92 | display: flex; 93 | justify-content: space-between; 94 | list-style-type: none; 95 | padding: 0; 96 | font-family: 'Poppins', 97 | sans-serif; 98 | max-width: 400px; 99 | } 100 | 101 | .user-info ul li { 102 | display: flex; 103 | align-items: center; 104 | } 105 | 106 | .user-info ul li strong { 107 | font-size: 0.9rem; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | .repo { 112 | background-color: #2a2a72; 113 | border-radius: 5px; 114 | display: inline-block; 115 | color: white; 116 | font-size: 0.7rem; 117 | padding: 0.25rem 0.5rem; 118 | margin-right: 0.5rem; 119 | margin-bottom: 0.5rem; 120 | text-decoration: none; 121 | } 122 | -------------------------------------------------------------------------------- /Hangman-Game/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hangman 7 | 8 | 9 | 10 | 11 |

Hangman

12 | 13 |

Guess the word!

14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 |
50 | 51 |
52 |
53 | 54 |
55 | 56 |
57 |
58 | 59 | 60 | 61 | 62 | 69 | 70 |
71 |

You've already entered this letter

72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /Hangman-Game/script.js: -------------------------------------------------------------------------------- 1 | const wordEl = document.getElementById('word'); 2 | const wrongLettersEl = document.getElementById('wrong-letters'); 3 | const playAgainBtn = document.getElementById('play-button'); 4 | const popup = document.getElementById('popup-container'); 5 | const notification = document.getElementById('notification-container'); 6 | const finalMessage = document.getElementById('final-message'); 7 | 8 | const figureParts = document.querySelectorAll('.figure-part'); 9 | 10 | const words = ['application', 'programming', 'interface', 'wizard']; 11 | 12 | let selectedWord = words[Math.floor(Math.random() * words.length)]; 13 | 14 | const correctLetters = []; 15 | const wrongLetters = []; 16 | 17 | // Show hidden word 18 | function displayWord() { 19 | wordEl.innerHTML = ` 20 | ${selectedWord 21 | .split('') 22 | .map( 23 | letter => ` 24 | 25 | ${correctLetters.includes(letter) ? letter : ''} 26 | 27 | ` 28 | ) 29 | .join('')} 30 | `; 31 | 32 | const innerWord = wordEl.innerText.replace(/\n/g, ''); 33 | 34 | if (innerWord === selectedWord) { 35 | finalMessage.innerText = "Hell yeah, you guessed it right!"; 36 | popup.style.display = 'flex'; 37 | } 38 | } 39 | 40 | // Update the wrong letters 41 | function updateWrongLettersEl() { 42 | // Display wrong letters 43 | wrongLettersEl.innerHTML = ` 44 | ${wrongLetters.length > 0 ? '

Wrong

' : ''} 45 | ${wrongLetters.map(letter => `${letter}`)} 46 | `; 47 | 48 | // Display parts 49 | figureParts.forEach((part, index) => { 50 | const errors = wrongLetters.length; 51 | 52 | if (index < errors) { 53 | part.style.display = 'block'; 54 | } else { 55 | part.style.display = 'none'; 56 | } 57 | }); 58 | 59 | // Check if lost 60 | if (wrongLetters.length === figureParts.length) { 61 | finalMessage.innerText = "All you had to do was to guess the goddamn word CJ!"; 62 | popup.style.display = 'flex'; 63 | } 64 | } 65 | 66 | // Show notification 67 | function showNotification() { 68 | notification.classList.add('show'); 69 | 70 | setTimeout(() => { 71 | notification.classList.remove('show'); 72 | }, 2000); 73 | } 74 | 75 | // Keydown letter press 76 | window.addEventListener('keydown', e => { 77 | // console.log(e.keyCode); 78 | if (e.keyCode >= 65 && e.keyCode <= 90) { 79 | 80 | const letter = e.key; 81 | 82 | if (selectedWord.includes(letter)) { 83 | if (!correctLetters.includes(letter)) { 84 | correctLetters.push(letter); 85 | 86 | displayWord(); 87 | } else { 88 | showNotification(); 89 | } 90 | } else { 91 | if (!wrongLetters.includes(letter)) { 92 | wrongLetters.push(letter); 93 | 94 | updateWrongLettersEl(); 95 | } else { 96 | showNotification(); 97 | } 98 | } 99 | } 100 | }); 101 | 102 | // Restart game and play again 103 | playAgainBtn.addEventListener('click', () => { 104 | // Empty arrays 105 | correctLetters.splice(0); 106 | wrongLetters.splice(0); 107 | 108 | selectedWord = words[Math.floor(Math.random() * words.length)]; 109 | 110 | displayWord(); 111 | 112 | updateWrongLettersEl(); 113 | 114 | popup.style.display = 'none'; 115 | }); 116 | 117 | displayWord(); 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Hangman-Game/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Nunito&display=swap"); 2 | * { 3 | box-sizing: border-box; 4 | font-family: "Nunito", sans-serif; 5 | } 6 | 7 | body { 8 | background-color: #0f181a; 9 | color: rgb(243, 241, 241); 10 | font-family: Arial, Helvetica, sans-serif; 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | height: 80vh; 15 | margin: 0; 16 | overflow: hidden; 17 | } 18 | 19 | h1 { 20 | margin-top: 1.8em; 21 | font-size: 3em; 22 | } 23 | 24 | .game-container { 25 | padding: 20px 30px; 26 | position: relative; 27 | margin: auto; 28 | height: 350px; 29 | width: 450px; 30 | } 31 | 32 | .figure-container { 33 | fill: transparent; 34 | stroke: wheat; 35 | stroke-width: 4px; 36 | stroke-linecap: round; 37 | } 38 | 39 | .figure-part { 40 | display: none; 41 | } 42 | 43 | .wrong-letters-container { 44 | position: absolute; 45 | top: 20px; 46 | right: 20px; 47 | display: flex; 48 | flex-direction: column; 49 | text-align: right; 50 | } 51 | 52 | .wrong-letters-container p { 53 | margin: 0 0 5px; 54 | } 55 | 56 | .wrong-letters-container span { 57 | font-size: 24px; 58 | } 59 | 60 | .word { 61 | display: flex; 62 | position: absolute; 63 | bottom: 10px; 64 | left: 50%; 65 | transform: translateX(-50%); 66 | } 67 | 68 | .letter { 69 | border-bottom: 3px solid #8be978; 70 | opacity: 0.7; 71 | display: inline-flex; 72 | font-size: 30px; 73 | align-items: center; 74 | justify-content: center; 75 | margin: 0 3px; 76 | height: 50px; 77 | width: 20px; 78 | } 79 | 80 | .popup-container { 81 | background-color: rgba(0, 0, 0, 0.3); 82 | position: fixed; 83 | top: 0; 84 | bottom: 0; 85 | left: 0; 86 | right: 0; 87 | display: none; 88 | align-items: center; 89 | justify-content: center; 90 | } 91 | 92 | .popup { 93 | background: #e24f4a; 94 | border-radius: 15px; 95 | box-shadow: 0 15px 10px 3px rgba(0, 0, 0, 0.1); 96 | padding: 50px; 97 | text-align: center; 98 | } 99 | 100 | .popup button { 101 | cursor: pointer; 102 | background-color: rgb(27, 27, 27); 103 | color: #cbe3f3; 104 | border-radius: 10px; 105 | border: 0; 106 | margin-top: 20px; 107 | padding: 12px 20px; 108 | font-size: 16px; 109 | } 110 | 111 | .popup button:active { 112 | transform: scale(0.98); 113 | } 114 | 115 | .popup button:focus { 116 | outline: 0; 117 | } 118 | 119 | .notification-container { 120 | background-color: rgba(0, 0, 0, 0.3); 121 | border-radius: 10px 10px 0 0; 122 | padding: 15px 20px; 123 | position: absolute; 124 | bottom: -50px; 125 | transition: transform 0.3s ease-in-out; 126 | } 127 | 128 | .notification-container p { 129 | margin: 0; 130 | } 131 | 132 | .notification-container.show { 133 | transform: translateY(-50px); 134 | } 135 | -------------------------------------------------------------------------------- /Meditate-App/bg12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Meditate-App/bg12.jpg -------------------------------------------------------------------------------- /Meditate-App/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Meditate 9 | 10 | 11 |

Meditate

12 | 13 | 14 | 19 | 20 | 21 |
22 |
23 | 24 | 25 |

26 | 27 |
28 | 29 |
30 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Meditate-App/script.js: -------------------------------------------------------------------------------- 1 | const container = document.getElementById('container'); 2 | const text = document.getElementById('text'); 3 | 4 | const totalTime = 7500; 5 | const breatheTime = (totalTime / 5) * 2; 6 | const holdTime = totalTime / 5; 7 | 8 | breathAnimation(); 9 | 10 | function breathAnimation() { 11 | text.innerText = 'Breathe In'; 12 | container.className = 'container grow'; 13 | 14 | if(text.innerText==="Breathe In") 15 | text.style.marginLeft= '5.4rem' 16 | 17 | setTimeout(() => { 18 | text.innerText = 'Hold'; 19 | if(text.innerText==="Hold") 20 | text.style.marginLeft= '7.5rem' 21 | 22 | setTimeout(() => { 23 | text.innerText = 'Breathe Out'; 24 | 25 | if(text.innerText==="Breathe Out") 26 | text.style.marginLeft= '4.8rem' 27 | 28 | container.className = 'container shrink'; 29 | }, holdTime); 30 | }, breatheTime); 31 | } 32 | 33 | setInterval(breathAnimation, totalTime); 34 | -------------------------------------------------------------------------------- /Meditate-App/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap'); 2 | 3 | * { 4 | font-family: 'Montserrat', 5 | sans-serif; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | background: #225e51 url('./bg12.jpg') no-repeat center center/cover; 11 | margin: 0; 12 | min-height: 100vh; 13 | overflow: hidden; 14 | display: flex; 15 | align-items: center; 16 | color: white; 17 | flex-direction: column; 18 | 19 | } 20 | 21 | .container { 22 | display: flex; 23 | align-items: center; 24 | justify-items: center; 25 | margin: auto; 26 | height: 300px; 27 | width: 300px; 28 | position: relative; 29 | transform: scale(1); 30 | } 31 | 32 | h1 { 33 | font-size: 3rem; 34 | margin-top: 4.2rem; 35 | } 36 | 37 | .circle { 38 | background-color: rgb(15, 59, 52); 39 | height: 100%; 40 | width: 100%; 41 | border-radius: 50%; 42 | position: absolute; 43 | z-index: -1; 44 | 45 | } 46 | 47 | #text { 48 | font-size: 1.5rem; 49 | margin-left: 1rem; 50 | color: #fffdfd; 51 | font-weight: bold; 52 | 53 | } 54 | 55 | 56 | .gradient-circle { 57 | background: conic-gradient(#55b7a4 0%, 58 | #4ca493 40%, 59 | rgb(224, 233, 228) 40%, 60 | rgb(245, 242, 242) 60%, 61 | #336d62 60%, 62 | #2a5b52 100%); 63 | height: 320px; 64 | width: 320px; 65 | z-index: -2; 66 | border-radius: 50%; 67 | position: absolute; 68 | top: -10px; 69 | left: -10px; 70 | box-shadow: 4px 8px 13px rgba(16, 61, 51, 0.9) 71 | } 72 | 73 | 74 | .pointer { 75 | background-color: #f7f7f7; 76 | border-radius: 50%; 77 | height: 20px; 78 | width: 20px; 79 | display: block; 80 | } 81 | 82 | .pointer-container { 83 | position: absolute; 84 | top: -40px; 85 | left: 140px; 86 | width: 20px; 87 | height: 190px; 88 | animation: rotate 7.5s linear forwards infinite; 89 | transform-origin: bottom center; 90 | } 91 | 92 | @keyframes rotate { 93 | from { 94 | transform: rotate(0deg); 95 | } 96 | 97 | to { 98 | transform: rotate(360deg); 99 | } 100 | } 101 | 102 | .container.grow { 103 | animation: grow 3s linear forwards; 104 | } 105 | 106 | @keyframes grow { 107 | from { 108 | transform: scale(1); 109 | } 110 | 111 | to { 112 | transform: scale(1.2); 113 | } 114 | } 115 | 116 | .container.shrink { 117 | animation: shrink 3s linear forwards; 118 | } 119 | 120 | @keyframes shrink { 121 | from { 122 | transform: scale(1.2); 123 | } 124 | 125 | to { 126 | transform: scale(1); 127 | } 128 | } 129 | 130 | 131 | audio:hover, 132 | audio:focus, 133 | audio:active { 134 | outline: none; 135 | box-shadow: 5px 5px 11px rgba(49, 148, 148, 0.4); 136 | -webkit-transform: scale(1.05); 137 | -moz-transform: scale(1.05); 138 | transform: scale(1.05); 139 | } 140 | 141 | audio { 142 | -webkit-transition: all 0.5s linear; 143 | -moz-transition: all 0.5s linear; 144 | -o-transition: all 0.5s linear; 145 | transition: all 0.5s linear; 146 | 147 | box-shadow: 2px 2px 12px 5px #55a3a8; 148 | 149 | border-radius: 89px; 150 | } -------------------------------------------------------------------------------- /Meditate-App/y2mate.com - 15 Minute Super Deep Meditation Music_ Relax Mind Body, Inner Peace, Relaxing Music, ☯2563B.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Meditate-App/y2mate.com - 15 Minute Super Deep Meditation Music_ Relax Mind Body, Inner Peace, Relaxing Music, ☯2563B.mp3 -------------------------------------------------------------------------------- /Modal-Menu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Modal Demo 7 | 8 | 9 | 10 | 11 | 12 | 31 | 32 |
33 | 36 | 37 |

Modal Demo

38 | 39 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius, dolores!

40 | 41 | 44 |
45 | 46 |
47 |

Demo as heck

48 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque odit, omnis corporis pariatur voluptas fugit quaerat dignissimos excepturi reprehenderit autem!

49 | 50 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsam, id. Nobis sunt assumenda, quidem enim totam quis vero cumque ea!

51 | 52 |

Ssup?

53 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Laudantium libero tempora itaque explicabo suscipit obcaecati deserunt, odit laboriosam nisi animi?

54 | 55 |

What's poppin' mate

56 | 57 | 62 |

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia recusandae dignissimos.

63 |
64 | 65 | 66 | 67 | 68 | 69 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Modal-Menu/script.js: -------------------------------------------------------------------------------- 1 | const toggle = document.getElementById("toggle") 2 | 3 | const close = document.getElementById("close") 4 | 5 | 6 | const open = document.getElementById("open") 7 | 8 | 9 | const modal = document.getElementById("modal") 10 | 11 | 12 | //toggle 13 | 14 | toggle.addEventListener("click", ()=> 15 | document.body.classList.toggle('show-nav')) 16 | 17 | 18 | 19 | // show modal 20 | 21 | open.addEventListener("click", () => modal.classList.add('show-modal')) 22 | 23 | 24 | // hide modal 25 | 26 | close.addEventListener("click", ()=> modal.classList.remove('show-modal')) 27 | 28 | 29 | // hide modal on outside click 30 | 31 | window.addEventListener("click", e=> e.target == modal ? 32 | modal.classList.remove('show-modal') :false) 33 | 34 | -------------------------------------------------------------------------------- /Modal-Menu/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=PT+Sans&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | font-family: "PT Sans", sans-serif; 6 | } 7 | 8 | :root { 9 | --modal-duration: 1s; 10 | --primary-color: #eb4545; 11 | --secondary-color: #643f2e; 12 | --tertiary-color: #b95638; 13 | } 14 | 15 | * { 16 | box-sizing: border-box; 17 | } 18 | 19 | body { 20 | margin: 0; 21 | transition: transform 0.6s ease-in-out; 22 | } 23 | 24 | body.show-nav { 25 | /* Width of nav */ 26 | transform: translateX(200px); 27 | } 28 | 29 | nav { 30 | background-color: var(--tertiary-color); 31 | border-right: 10px solid rgb(58, 10, 10, 0.2); 32 | color: whitesmoke; 33 | position: fixed; 34 | top: 0; 35 | left: 0; 36 | width: 200px; 37 | height: 100vh; 38 | z-index: 100; 39 | transform: translateX(-100%); 40 | } 41 | 42 | nav .logo { 43 | padding: 30px 0; 44 | text-align: center; 45 | } 46 | 47 | nav .logo img { 48 | height: 95px; 49 | width: 95px; 50 | border-radius: 30px; 51 | box-shadow: 3px 3px 7px 2px rgba(0, 0, 0, 0.3); 52 | } 53 | 54 | nav ul { 55 | padding: 0; 56 | list-style-type: none; 57 | margin: 0; 58 | font-size: 25px; 59 | } 60 | 61 | nav ul li { 62 | border-bottom: 6px solid rgba(200, 200, 200, 0.1); 63 | padding: 20px; 64 | } 65 | 66 | nav ul li:first-of-type { 67 | border-top: 6px solid rgba(200, 200, 200, 0.1); 68 | } 69 | 70 | nav ul li a { 71 | color: whitesmoke; 72 | text-decoration: none; 73 | } 74 | 75 | nav ul li a:hover { 76 | text-decoration: underline; 77 | } 78 | 79 | header { 80 | background-color: var(--primary-color); 81 | color: whitesmoke; 82 | font-size: 130%; 83 | position: relative; 84 | padding: 40px 15px; 85 | text-align: center; 86 | } 87 | 88 | header h1 { 89 | margin: 0; 90 | } 91 | 92 | header p { 93 | margin: 30px 0; 94 | } 95 | 96 | button, 97 | input[type="submit"] { 98 | background-color: var(--secondary-color); 99 | border: 0; 100 | border-radius: 5px; 101 | color: whitesmoke; 102 | cursor: pointer; 103 | padding: 8px 12px; 104 | } 105 | 106 | button:focus { 107 | outline: none; 108 | } 109 | 110 | .toggle { 111 | background-color: rgba(7, 6, 6, 0.3); 112 | position: absolute; 113 | top: 20px; 114 | left: 20px; 115 | } 116 | 117 | .cta-btn { 118 | padding: 12px 30px; 119 | font-size: 20px; 120 | } 121 | 122 | .container { 123 | padding: 15px; 124 | margin: 0 auto; 125 | max-width: 100%; 126 | width: 800px; 127 | } 128 | 129 | .modal-container { 130 | background-color: rgba(0, 0, 0, 0.6); 131 | display: none; 132 | position: fixed; 133 | top: 0; 134 | left: 0; 135 | right: 0; 136 | bottom: 0; 137 | } 138 | 139 | .modal-container.show-modal { 140 | display: block; 141 | } 142 | 143 | .modal { 144 | background-color: #fff; 145 | border-radius: 15px; 146 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.9); 147 | position: absolute; 148 | overflow: hidden; 149 | top: 50%; 150 | left: 50%; 151 | transform: translate(-50%, -50%); /*center placement*/ 152 | max-width: 100%; 153 | width: 400px; 154 | animation-name: modalopen; 155 | animation-duration: var(--modal-duration); 156 | } 157 | 158 | .modal-header { 159 | background: var(--primary-color); 160 | color: #fff; 161 | padding: 15px; 162 | } 163 | 164 | .modal-header h3 { 165 | margin: 0; 166 | } 167 | 168 | .modal-content { 169 | padding: 20px; 170 | } 171 | 172 | .modal-form div { 173 | margin: 15px 0; 174 | } 175 | 176 | .modal-form label { 177 | display: block; 178 | margin-bottom: 5px; 179 | } 180 | 181 | .modal-form .form-input { 182 | padding: 8px; 183 | width: 100%; 184 | } 185 | 186 | .close-btn { 187 | background: transparent; 188 | font-size: 25px; 189 | position: absolute; 190 | top: 0; 191 | right: 0; 192 | } 193 | 194 | @keyframes modalopen { 195 | from { 196 | opacity: 0; 197 | } 198 | 199 | to { 200 | opacity: 1; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Movie-Info/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Movie Info 7 | 8 | 9 | 10 | 11 |
12 |
13 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Movie-Info/script.js: -------------------------------------------------------------------------------- 1 | const apiUrl = 2 | "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=04c35731a5ee918f014970082a0088b1&page=1"; 3 | const imagePath = "https://image.tmdb.org/t/p/w1280"; 4 | const searchApi = 5 | "https://api.themoviedb.org/3/search/movie?&api_key=04c35731a5ee918f014970082a0088b1&query="; 6 | 7 | const main = document.getElementById("main"); 8 | const form = document.getElementById("form"); 9 | const search = document.getElementById("search"); 10 | 11 | // most popular in home page 12 | getMovies(apiUrl); 13 | 14 | async function getMovies(url) { 15 | const resp = await fetch(url); 16 | const respData = await resp.json(); 17 | 18 | console.log(respData); 19 | 20 | showMovies(respData.results); 21 | } 22 | 23 | let showMovies = (movies) => { 24 | // clear main 25 | main.innerHTML = ""; 26 | 27 | movies.forEach((movie) => { 28 | const { poster_path, title, vote_average, overview, release_date } = movie; 29 | 30 | const movieEl = document.createElement("div"); 31 | movieEl.classList.add("movie"); 32 | 33 | movieEl.innerHTML = ` 34 | 35 | 36 | ${title} 40 |
41 |

${title}

42 | ${vote_average} 45 |
46 | 47 |
48 |

Overview:

49 | ${overview} 50 |
51 |

52 | Release Date:

53 |

${release_date}

54 |
55 | 56 | 57 | `; 58 | 59 | main.appendChild(movieEl); 60 | }); 61 | } 62 | 63 | function getClassByRate(vote) { 64 | if (vote >= 8) { 65 | return "green"; 66 | } else if (vote >= 5) { 67 | return "orange"; 68 | } else { 69 | return "red"; 70 | } 71 | } 72 | 73 | form.addEventListener("submit", (e) => { 74 | e.preventDefault(); 75 | 76 | const searchTerm = search.value; 77 | 78 | if (searchTerm) { 79 | getMovies(searchApi + searchTerm); 80 | 81 | search.value = ""; 82 | } 83 | }); 84 | -------------------------------------------------------------------------------- /Movie-Info/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap'); 2 | * { 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | 8 | background-color: #f3eaea; 9 | 10 | font-family: 'Noto Sans', 11 | sans-serif; 12 | 13 | 14 | } 15 | 16 | header { 17 | background-color: #f3eaea; 18 | display: flex; 19 | justify-content: flex-end; 20 | padding: 1rem; 21 | } 22 | 23 | .search { 24 | background-color: transparent; 25 | border: 2px solid #dbc169; 26 | border-radius: 50px; 27 | color: rgb(29, 23, 23); 28 | font-family: inherit; 29 | font-size: 1rem; 30 | padding: 0.5rem 1rem; 31 | } 32 | 33 | .search::placeholder { 34 | color: #000000; 35 | } 36 | 37 | .search:focus { 38 | background-color: #f1eae9; 39 | outline: none; 40 | } 41 | 42 | 43 | main { 44 | display: flex; 45 | flex-wrap: wrap; 46 | 47 | } 48 | 49 | .movie { 50 | background-color: #f5eeed; 51 | border-radius: 12px; 52 | box-shadow: 0 4px 5px rgba(0, 0, 0, 0.3); 53 | overflow: hidden; 54 | position: relative; 55 | 56 | margin: 1rem; 57 | width: 300px; 58 | 59 | } 60 | 61 | .movie img:hover{ 62 | opacity: .89; 63 | 64 | } 65 | 66 | .movie img { 67 | width: 100%; 68 | } 69 | 70 | .movie-info { 71 | color: #111; 72 | display: flex; 73 | align-items: center; 74 | justify-content: space-between; 75 | padding: 0.5rem 1rem 1rem; 76 | letter-spacing: 0.5px; 77 | } 78 | 79 | .movie-info h3 { 80 | margin: 0; 81 | } 82 | 83 | .movie-info span { 84 | background-color:transparent; 85 | border-radius: 3px; 86 | font-weight: bold; 87 | padding: 0.25rem 0.5rem; 88 | } 89 | .movie-info span.green { 90 | color: rgb(29, 104, 29); 91 | } 92 | 93 | .movie-info span.orange { 94 | color: rgb(151, 115, 47); 95 | } 96 | 97 | .movie-info span.red { 98 | color: rgb(189, 42, 42); 99 | } 100 | 101 | .overview { 102 | background-color: #fff; 103 | padding: 2rem; 104 | position: absolute; 105 | max-height: 100%; 106 | overflow: auto; 107 | left: 0; 108 | bottom: 0; 109 | right: 0; 110 | transform: translateY(101%); 111 | transition: transform 0.4s ease-in-out; 112 | } 113 | 114 | .overview h3 { 115 | margin-top: 0; 116 | } 117 | 118 | .movie:hover .overview { 119 | transform: translateY(0); 120 | } 121 | 122 | 123 | .date2{ 124 | margin-top: -1em; 125 | } -------------------------------------------------------------------------------- /Movie-Seat-Booking/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Movie Seat Booking 10 | 11 | 12 | 13 |
14 | 15 | 21 |
22 | 23 | 37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | 103 |

104 | You have selected 0 seats for a price of $0 105 |

106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /Movie-Seat-Booking/script.js: -------------------------------------------------------------------------------- 1 | const container = document.querySelector('.container') 2 | 3 | const seats = document.querySelectorAll('.row .seat:not(.occupied) ') 4 | 5 | const count = document.getElementById('count') 6 | 7 | const total = document.getElementById('total') 8 | 9 | const movieSelect = document.getElementById('movie') 10 | 11 | 12 | populateUI() 13 | let ticketPrice = +movieSelect.value; 14 | 15 | //save selected movie index & price 16 | 17 | function setMovieData(movieIndex, moviePrice){ 18 | localStorage.setItem(' selectedMovieIndex' , movieIndex) 19 | localStorage.setItem(' selectedMoviePrice' , moviePrice) 20 | } 21 | 22 | //updating total and count 23 | function updateSelectedCount(){ 24 | const selectedSeats = document.querySelectorAll('.row .seat.selected') 25 | 26 | 27 | 28 | 29 | 30 | //copy selected seats into array 31 | //map thru array 32 | //return a new array index 33 | 34 | 35 | const seatsIndex = [...selectedSeats].map( function(seat){ 36 | 37 | return [...seats].indexOf(seat) 38 | 39 | }) 40 | 41 | 42 | localStorage.setItem('selectedSeats' , JSON.stringify(seatsIndex)) 43 | 44 | const selectedSeatsCount = selectedSeats.length 45 | 46 | count.innerText = selectedSeatsCount 47 | total.innerText = selectedSeatsCount * ticketPrice 48 | 49 | 50 | 51 | 52 | } 53 | 54 | 55 | // get data from local storage and populate UI 56 | function populateUI(){ 57 | 58 | const selectedSeats = JSON.parse(localStorage.getItem('selectedSeats')) 59 | 60 | if(selectedSeats!== null && selectedSeats.length >0){ 61 | seats.forEach((seat, index)=>{ 62 | if(selectedSeats.indexOf(index)>-1) 63 | seat.classList.add('selected') 64 | 65 | }) 66 | } 67 | 68 | 69 | const selectedMovieIndex = localStorage.getItem('selectedMovieIndex') 70 | 71 | if(selectedMovieIndex !==null) 72 | movieSelect.selected = selectedMovieIndex 73 | 74 | } 75 | 76 | //movie select event 77 | 78 | movieSelect.addEventListener('change', e=>{ 79 | ticketPrice = +e.target.value 80 | updateSelectedCount() 81 | }) 82 | 83 | //seat click event 84 | container.addEventListener('click',(e) =>{ 85 | if 86 | (e.target.classList.contains('seat') && 87 | !e.target.classList.contains('occupied')) 88 | { 89 | e.target.classList.toggle('selected') 90 | 91 | 92 | 93 | updateSelectedCount() 94 | } 95 | }) 96 | 97 | 98 | //initial count & total set 99 | updateSelectedCount() 100 | -------------------------------------------------------------------------------- /Movie-Seat-Booking/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=B612&display=swap"); 2 | 3 | * { 4 | font-family: "B612", sans-serif; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | background-color: #091111; 10 | display: flex; 11 | flex-direction: column; 12 | color: rgb(243, 240, 235); 13 | align-items: center; 14 | height: 100vh; 15 | justify-content: center; 16 | margin: 0; 17 | } 18 | 19 | .movie-container { 20 | margin: 20px 0; 21 | } 22 | 23 | .movie-container select { 24 | background-color: #fff; 25 | border: 0; 26 | border-radius: 5px; 27 | font-size: 14px; 28 | margin-left: 10px; 29 | padding: 5px 15px 5px 15px; 30 | -moz-appearance: none; 31 | -webkit-appearance: none; 32 | appearance: none; 33 | } 34 | 35 | .seat { 36 | background-color: #444451; 37 | height: 12px; 38 | width: 15px; 39 | margin: 3px; 40 | border-top-left-radius: 10px; 41 | border-top-right-radius: 10px; 42 | } 43 | 44 | .seat.selected { 45 | background-color: #6feaf6; 46 | } 47 | .row { 48 | display: flex; 49 | } 50 | 51 | .seat.occupied { 52 | background-color: whitesmoke; 53 | } 54 | 55 | .seat:nth-of-type(2) { 56 | margin-right: 18px; 57 | } 58 | 59 | .seat:nth-last-of-type(2) { 60 | margin-left: 18px; 61 | } 62 | 63 | .seat:not(.occupied):hover { 64 | cursor: pointer; 65 | transform: scale(1.2); 66 | } 67 | 68 | .showcase .seat:not(.occupied):hover { 69 | cursor: default; 70 | transform: scale(1); 71 | } 72 | 73 | .showcase { 74 | padding: 5px 10px; 75 | border-radius: 5px; 76 | color: #777; 77 | list-style-type: none; 78 | display: flex; 79 | justify-content: space-between; 80 | background-color: rgba(24, 18, 18, 0.1); 81 | } 82 | 83 | .showcase li { 84 | display: flex; 85 | align-items: center; 86 | justify-content: center; 87 | margin: 0 10px; 88 | } 89 | 90 | .showcase li small { 91 | margin-left: 2px; 92 | } 93 | 94 | .screen { 95 | background-color: white; 96 | height: 70px; 97 | width: 100%; 98 | margin: 15px 0px; 99 | transform: rotateX(-45deg); 100 | box-shadow: 0 3px 50px rgba(230, 225, 225, 0.5); 101 | } 102 | 103 | .container { 104 | perspective: 1000px; 105 | margin-bottom: 30px; 106 | } 107 | 108 | p.text span { 109 | color: #6feaf6; 110 | } 111 | 112 | p.text { 113 | margin: 5px 0; 114 | } 115 | -------------------------------------------------------------------------------- /Music-Player/images/hey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/images/hey.jpg -------------------------------------------------------------------------------- /Music-Player/images/summer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/images/summer.jpg -------------------------------------------------------------------------------- /Music-Player/images/ukulele.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/images/ukulele.jpg -------------------------------------------------------------------------------- /Music-Player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | Music Player 13 | 14 | 15 |

Music Player

16 | 17 |
18 |
19 |

20 |
21 |
22 |
23 |
24 | 25 | 26 | 27 |
28 | music-cover 29 |
30 | 41 |
42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Music-Player/music/hey.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/music/hey.mp3 -------------------------------------------------------------------------------- /Music-Player/music/summer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/music/summer.mp3 -------------------------------------------------------------------------------- /Music-Player/music/ukulele.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/Music-Player/music/ukulele.mp3 -------------------------------------------------------------------------------- /Music-Player/script.js: -------------------------------------------------------------------------------- 1 | const musicContainer = document.getElementById('music-container'); 2 | const playBtn = document.getElementById('play'); 3 | const prevBtn = document.getElementById('prev'); 4 | const nextBtn = document.getElementById('next'); 5 | 6 | const audio = document.getElementById('audio'); 7 | const progress = document.getElementById('progress'); 8 | const progressContainer = document.getElementById('progress-container'); 9 | const title = document.getElementById('title'); 10 | const cover = document.getElementById('cover'); 11 | 12 | // Song titles 13 | const songs = ['hey', 'summer', 'ukulele']; 14 | 15 | // Keep track of song 16 | let songIndex = 1; 17 | 18 | // Initially load song details into DOM 19 | loadSong(songs[songIndex]); 20 | 21 | // Update song details 22 | function loadSong(song) { 23 | title.innerText = song; 24 | audio.src = `music/${song}.mp3`; 25 | cover.src = `images/${song}.jpg`; 26 | } 27 | 28 | // Play song 29 | let playSong =() => { 30 | musicContainer.classList.add('play'); 31 | playBtn.querySelector('i.fas').classList.remove('fa-play'); 32 | playBtn.querySelector('i.fas').classList.add('fa-pause'); 33 | 34 | audio.play(); 35 | } 36 | 37 | // Pause song 38 | let pauseSong =()=> { 39 | musicContainer.classList.remove('play'); 40 | playBtn.querySelector('i.fas').classList.add('fa-play'); 41 | playBtn.querySelector('i.fas').classList.remove('fa-pause'); 42 | 43 | audio.pause(); 44 | } 45 | 46 | // Previous song 47 | let prevSong = () => { 48 | songIndex--; 49 | 50 | if (songIndex < 0) { 51 | songIndex = songs.length - 1; 52 | } 53 | 54 | loadSong(songs[songIndex]); 55 | 56 | playSong(); 57 | } 58 | 59 | // Next song 60 | let nextSong = () => { 61 | songIndex++; 62 | 63 | if (songIndex > songs.length - 1) { 64 | songIndex = 0; 65 | } 66 | 67 | loadSong(songs[songIndex]); 68 | 69 | playSong(); 70 | } 71 | 72 | // Update progress bar 73 | let updateProgress = (e) => { 74 | const { duration, currentTime } = e.srcElement; 75 | const progressPercent = (currentTime / duration) * 100; 76 | progress.style.width = `${progressPercent}%`; 77 | } 78 | 79 | // Set progress bar 80 | let setProgress = (e) => { 81 | const width = this.clientWidth; 82 | const clickX = e.offsetX; 83 | const duration = audio.duration; 84 | 85 | audio.currentTime = (clickX / width) * duration; 86 | } 87 | 88 | // Event listeners 89 | playBtn.addEventListener('click', () => { 90 | const isPlaying = musicContainer.classList.contains('play'); 91 | 92 | if (isPlaying) { 93 | pauseSong(); 94 | } else { 95 | playSong(); 96 | } 97 | }); 98 | 99 | // Change song 100 | prevBtn.addEventListener('click', prevSong); 101 | nextBtn.addEventListener('click', nextSong); 102 | 103 | // Time/song update 104 | audio.addEventListener('timeupdate', updateProgress); 105 | 106 | // Click on progress bar 107 | progressContainer.addEventListener('click', setProgress); 108 | 109 | // Song ends 110 | audio.addEventListener('ended', nextSong); -------------------------------------------------------------------------------- /Music-Player/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300&display=swap'); 2 | 3 | *{ 4 | font-family: 'Poppins', 5 | sans-serif; box-sizing: border-box; 6 | 7 | } 8 | body { 9 | background-image: linear-gradient(0deg, 10 | rgba(247, 247, 247, 1) 23.8%, 11 | rgba(252, 221, 221, 1) 92%); 12 | height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | margin: 0; 18 | } 19 | 20 | .music-container { 21 | background-color: rgb(255, 255, 255); 22 | border-radius: 95px; 23 | box-shadow: 0px 20px 28px 0 rgba(245, 187, 187, 0.6); 24 | display: flex; 25 | padding: 20px 30px; 26 | position: relative; 27 | margin: 100px 0; 28 | z-index: 10; 29 | } 30 | 31 | .img-container { 32 | position: relative; 33 | width: 110px; 34 | } 35 | 36 | .img-container::after { 37 | content: ''; 38 | background-color: rgb(255, 255, 255); 39 | border-radius: 50%; 40 | position: absolute; 41 | bottom: 100%; 42 | left: 50%; 43 | width: 20px; 44 | height: 20px; 45 | transform: translate(-50%, 100%); 46 | } 47 | 48 | .img-container img { 49 | border-radius: 50%; 50 | object-fit: cover; 51 | height: 110px; 52 | width: inherit; 53 | position: absolute; 54 | bottom: 0; 55 | left: 0; 56 | animation: rotate 3s linear infinite; 57 | 58 | animation-play-state: paused; 59 | } 60 | 61 | .music-container.play .img-container img { 62 | animation-play-state: running; 63 | } 64 | 65 | @keyframes rotate { 66 | from { 67 | transform: rotate(0deg); 68 | } 69 | 70 | to { 71 | transform: rotate(360deg); 72 | } 73 | } 74 | 75 | .navigation { 76 | display: flex; 77 | align-items: center; 78 | justify-content: center; 79 | z-index: 1; 80 | } 81 | 82 | .action-btn { 83 | background-color: #fff; 84 | border: 0; 85 | color: #a555a5; 86 | font-size: 30px; 87 | cursor: pointer; 88 | padding: 10px; 89 | margin: 0 20px; 90 | } 91 | 92 | .action-btn:hover{ 93 | transition: 120ms transform ease-in; 94 | transform:scale(1.08) 95 | } 96 | .action-btn.action-btn-big { 97 | color: #844f92; 98 | font-size: 30px; 99 | } 100 | 101 | .action-btn:focus { 102 | outline: 0; 103 | } 104 | 105 | .music-info { 106 | background-color: rgba(255, 249, 252, 0.5); 107 | border-radius: 45px 45px 10px 10px; 108 | position: absolute; 109 | top: 0; 110 | left: 20px; 111 | width: calc(100% - 40px); 112 | padding: 10px 10px 10px 150px; 113 | opacity: 0; 114 | transform: translateY(0%); 115 | transition: transform 0.3s ease-in, opacity 0.3s ease-in; 116 | z-index: 0; 117 | } 118 | 119 | .music-container.play .music-info { 120 | opacity: 1; 121 | transform: translateY(-100%); 122 | } 123 | 124 | .music-info h4 { 125 | margin: 0; 126 | } 127 | 128 | .progress-container { 129 | background: #fff; 130 | border-radius: 5px; 131 | cursor: pointer; 132 | margin: 10px 0; 133 | height: 4px; 134 | width: 100%; 135 | } 136 | 137 | .progress { 138 | background-color: #fe8daa; 139 | border-radius: 5px; 140 | height: 100%; 141 | width: 0%; 142 | transition: width 0.1s linear; 143 | } 144 | -------------------------------------------------------------------------------- /New-Year-Countdown/README.md: -------------------------------------------------------------------------------- 1 | # There's a .gif file attached as a pre-loader. I didn't add it but you can remove the comments for the pre-loader in the files to generate this loader to avoid temporary "0" values when the page reloads. 2 | -------------------------------------------------------------------------------- /New-Year-Countdown/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | New Year Countdown 10 | 11 | 12 | 13 |
14 | 15 |

New Year Countdown

16 | 17 |
18 |
19 |

00

20 | days 21 |
22 |
23 |

00

24 | hours 25 |
26 |
27 |

00

28 | minutes 29 |
30 |
31 |

00

32 | seconds 33 |
34 |
35 | 36 | 37 |

to

38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /New-Year-Countdown/loaderx.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/New-Year-Countdown/loaderx.gif -------------------------------------------------------------------------------- /New-Year-Countdown/script.js: -------------------------------------------------------------------------------- 1 | const days = document.getElementById('days') 2 | const hours = document.getElementById('hours') 3 | const minutes = document.getElementById('minutes') 4 | const seconds = document.getElementById('seconds') 5 | const countdown = document.getElementById('countdown') 6 | const year = document.getElementById("year") 7 | // const loading = document.getElementById("loading") 8 | 9 | 10 | 11 | const currentYear = new Date().getFullYear() 12 | 13 | const newYearTime = new Date(`January 01 ${currentYear +1} 00:00:00`) 14 | 15 | 16 | // coming year 17 | year.innerText = currentYear + 1 18 | 19 | 20 | 21 | // update countdown time 22 | let cd = updateCountDown=()=>{ 23 | 24 | const currentTime = new Date() 25 | 26 | const diff = newYearTime - currentTime 27 | 28 | const d = Math.floor(diff / 1000 / 60 / 60 / 24) 29 | 30 | const h = Math.floor(diff / 1000 / 60 / 60 ) % 24 31 | 32 | const m = Math.floor(diff / 1000 / 60 ) % 60 33 | 34 | const s = Math.floor(diff / 1000 ) % 60 35 | 36 | // add values to DOM 37 | days.innerHTML = d 38 | hours.innerHTML = h < 10 ? '0' + h : h 39 | minutes.innerHTML = m < 10 ? '0' + m : m 40 | seconds.innerHTML = s < 10 ? '0' + s : s 41 | 42 | } 43 | 44 | 45 | //show preloader 46 | // setTimeout( ()=>{ 47 | 48 | // loading.remove() 49 | 50 | // countdown.style.display = 'flex' 51 | // }, 1000) 52 | 53 | // run every sec 54 | setInterval(updateCountDown, 1000) 55 | 56 | updateCountDown() -------------------------------------------------------------------------------- /New-Year-Countdown/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400&display=swap"); 2 | 3 | * { 4 | box-sizing: border-box; 5 | font-family: "Poppins", sans-serif; 6 | } 7 | 8 | body { 9 | background-image: url("https://images.unsplash.com/photo-1492998680170-81f8863d8d2d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=925&q=80"); 10 | background-repeat: no-repeat; 11 | background-size: cover; 12 | background-position: center center; 13 | height: 100vh; 14 | color: #fff; 15 | font-family: "Lato", sans-serif; 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; 19 | justify-content: center; 20 | text-align: center; 21 | margin: 0; 22 | overflow: hidden; 23 | background-blend-mode: hard-light; 24 | } 25 | 26 | /* dark overlay */ 27 | body::after { 28 | content: ""; 29 | position: absolute; 30 | top: 0; 31 | left: 0; 32 | width: 100%; 33 | height: 100%; 34 | background-color: rgba(0, 0, 0, 0.77); 35 | } 36 | 37 | body * { 38 | z-index: 1; 39 | } 40 | 41 | h1 { 42 | font-size: 60px; 43 | margin: -80px 0 40px; 44 | color: whitesmoke; 45 | } 46 | 47 | .countdown { 48 | display: flex; 49 | transform: scale(2); 50 | } 51 | 52 | .time { 53 | display: flex; 54 | flex-direction: column; 55 | align-items: center; 56 | justify-content: center; 57 | margin: 15px; 58 | } 59 | 60 | .time h2 { 61 | margin: 0 0 5px; 62 | color: rgb(194, 190, 190); 63 | } 64 | 65 | @media (max-width: 500px) { 66 | h1 { 67 | font-size: 45px; 68 | } 69 | 70 | .time { 71 | margin: 5px; 72 | } 73 | 74 | .time h2 { 75 | font-size: 12px; 76 | margin: 0; 77 | } 78 | 79 | .time small { 80 | font-size: 10px; 81 | } 82 | } 83 | 84 | .year { 85 | font-size: 200px; 86 | /* z-index: -1; */ 87 | position: absolute; 88 | bottom: 20px; 89 | left: 50%; 90 | transform: translateX(-50%); 91 | color: rgb(216, 216, 226); 92 | } 93 | 94 | /* .loading { 95 | opacity: 0.5; 96 | } */ 97 | 98 | .to { 99 | font-size: 4rem; 100 | color: rgb(184, 247, 228); 101 | } 102 | -------------------------------------------------------------------------------- /OG-Video-Player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Custom Video Player 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |

OG Video Player

20 | 21 | 24 | 25 |
26 | 29 | 30 | 34 | 35 | 36 | 38 | 39 | 00:00 40 |
41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /OG-Video-Player/noise12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/OG-Video-Player/noise12.png -------------------------------------------------------------------------------- /OG-Video-Player/poster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proghead00/Ultimate-JS-Projects-Collection/54411c66a6cd59b628ae457a4d03573c8a52fb79/OG-Video-Player/poster.jpg -------------------------------------------------------------------------------- /OG-Video-Player/progress.css: -------------------------------------------------------------------------------- 1 | /* SOURCE: https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ */ 2 | 3 | input[type="range"] { 4 | -webkit-appearance: none; /* Hides the slider so that custom slider can be made */ 5 | width: 100%; /* Specific width is required for Firefox. */ 6 | background: transparent; /* Otherwise white in Chrome */ 7 | } 8 | 9 | input[type="range"]::-webkit-slider-thumb { 10 | -webkit-appearance: none; 11 | } 12 | 13 | input[type="range"]:focus { 14 | outline: none; /* Removes the blue border. You should probably do some kind of focus styling for accessibility reasons though. */ 15 | } 16 | 17 | input[type="range"]::-ms-track { 18 | width: 100%; 19 | cursor: pointer; 20 | 21 | /* Hides the slider so custom styles can be added */ 22 | background: transparent; 23 | border-color: transparent; 24 | color: transparent; 25 | } 26 | 27 | /* Special styling for WebKit/Blink */ 28 | input[type="range"]::-webkit-slider-thumb { 29 | -webkit-appearance: none; 30 | border: 1px solid #000000; 31 | height: 36px; 32 | width: 16px; 33 | border-radius: 3px; 34 | background: #ffffff; 35 | cursor: pointer; 36 | margin-top: -14px; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */ 37 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; /* Add cool effects to your sliders! */ 38 | } 39 | 40 | /* All the same stuff for Firefox */ 41 | input[type="range"]::-moz-range-thumb { 42 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 43 | border: 1px solid #000000; 44 | height: 36px; 45 | width: 16px; 46 | border-radius: 3px; 47 | background: #ffffff; 48 | cursor: pointer; 49 | } 50 | 51 | /* All the same stuff for IE */ 52 | input[type="range"]::-ms-thumb { 53 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 54 | border: 1px solid #000000; 55 | height: 36px; 56 | width: 16px; 57 | border-radius: 3px; 58 | background: #ffffff; 59 | cursor: pointer; 60 | } 61 | 62 | input[type="range"]::-webkit-slider-runnable-track { 63 | width: 100%; 64 | height: 8.4px; 65 | cursor: pointer; 66 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 67 | background: #3071a9; 68 | border-radius: 1.3px; 69 | border: 0.2px solid #010101; 70 | } 71 | 72 | input[type="range"]:focus::-webkit-slider-runnable-track { 73 | background: #367ebd; 74 | } 75 | 76 | input[type="range"]::-moz-range-track { 77 | width: 100%; 78 | height: 8.4px; 79 | cursor: pointer; 80 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 81 | background: #3071a9; 82 | border-radius: 1.3px; 83 | border: 0.2px solid #010101; 84 | } 85 | 86 | input[type="range"]::-ms-track { 87 | width: 100%; 88 | height: 8.4px; 89 | cursor: pointer; 90 | background: transparent; 91 | border-color: transparent; 92 | border-width: 16px 0; 93 | color: transparent; 94 | } 95 | input[type="range"]::-ms-fill-lower { 96 | background: #2a6495; 97 | border: 0.2px solid #010101; 98 | border-radius: 2.6px; 99 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 100 | } 101 | input[type="range"]:focus::-ms-fill-lower { 102 | background: #3071a9; 103 | } 104 | input[type="range"]::-ms-fill-upper { 105 | background: #3071a9; 106 | border: 0.2px solid #010101; 107 | border-radius: 2.6px; 108 | box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; 109 | } 110 | input[type="range"]:focus::-ms-fill-upper { 111 | background: #367ebd; 112 | } 113 | -------------------------------------------------------------------------------- /OG-Video-Player/script.js: -------------------------------------------------------------------------------- 1 | const video = document.getElementById('video'); 2 | const play = document.getElementById('play'); 3 | const stop = document.getElementById('stop'); 4 | const progress = document.getElementById('progress'); 5 | const timestamp = document.getElementById('timestamp'); 6 | 7 | // play/pause video 8 | 9 | function toggleVideoStatus() { 10 | if (video.paused) { 11 | video.play(); 12 | } else { 13 | video.pause(); 14 | } 15 | } 16 | 17 | 18 | 19 | // update play/pause icon 20 | 21 | function updatePlayIcon(){ 22 | if(video.paused) 23 | play.innerHTML = ' ' 24 | else 25 | play.innerHTML = ' ' 26 | } 27 | 28 | 29 | 30 | // update progress and timestamp 31 | 32 | function updateProgress(){ 33 | progress.value = (video.currentTime / video.duration)*100; // percentage 34 | 35 | 36 | //get minutes 37 | 38 | let mins = Math.floor(video.currentTime/60) 39 | 40 | if(mins < 10){ 41 | mins='0' + String(mins) 42 | 43 | } 44 | 45 | 46 | // get seconds 47 | let secs = Math.floor(video.currentTime % 60) 48 | if(secs < 10){ 49 | mins='0' + String(secs) 50 | 51 | } 52 | 53 | 54 | timestamp.innerHTML = `${mins}:${secs}` 55 | } 56 | 57 | 58 | 59 | 60 | 61 | // change video frame to the clicked progress 62 | 63 | function setVideoProgress(){ 64 | video.currentTime = (+progress.value * video.duration)/100 65 | } 66 | 67 | 68 | 69 | 70 | 71 | // stop video 72 | 73 | function stopVideo(){ 74 | video.currentTime = 0; 75 | video.pause() 76 | } 77 | // event listeners 78 | 79 | video.addEventListener("click", toggleVideoStatus) 80 | video.addEventListener("pause", updatePlayIcon) 81 | video.addEventListener("play", updatePlayIcon) 82 | video.addEventListener("timeupdate", updateProgress) 83 | 84 | 85 | play.addEventListener("click", toggleVideoStatus) 86 | 87 | stop.addEventListener("click", stopVideo) 88 | 89 | progress.addEventListener('change', setVideoProgress) -------------------------------------------------------------------------------- /OG-Video-Player/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap"); 2 | 3 | * { 4 | font-family: "Montserrat", sans-serif; 5 | box-sizing: border-box; 6 | } 7 | 8 | body { 9 | display: flex; 10 | flex-direction: column; 11 | align-items: center; 12 | justify-content: center; 13 | max-height: 100vh; 14 | background-color: rgb(236, 202, 208); 15 | z-index: -1; 16 | } 17 | 18 | h1 { 19 | margin-top: 2.4em; 20 | text-align: center; 21 | color: rgb(26, 19, 19); 22 | } 23 | 24 | .screen { 25 | cursor: pointer; 26 | width: 50%; 27 | background-color: #000 !important; 28 | border-radius: 0px 20px 0px 0px; 29 | box-shadow: 3px 7px 15px 8px rgb(0, 0, 0, 0.4); 30 | } 31 | 32 | @media (max-width: 800px) { 33 | .screen, 34 | .controls { 35 | width: 90% !important; 36 | } 37 | h1 { 38 | font-size: 26px; 39 | } 40 | } 41 | 42 | .controls { 43 | background-color: #000; 44 | color: wheat; 45 | width: 50%; 46 | box-shadow: 3px 7px 15px 6px rgb(0, 0, 0, 0.4); 47 | border-radius: 0px 0px 0px 20px; 48 | 49 | display: flex; 50 | justify-content: center; 51 | align-items: center; 52 | padding: 30px; 53 | } 54 | 55 | .controls .btn { 56 | border: 0; 57 | background: transparent; 58 | cursor: pointer; 59 | } 60 | .controls .fa-play { 61 | color: rgb(100, 212, 134); 62 | } 63 | .controls .fa-stop { 64 | color: rgb(216, 25, 25); 65 | } 66 | .controls .fa-pause { 67 | color: rgb(238, 245, 240); 68 | } 69 | 70 | .controls .timestamp { 71 | color: wheat; 72 | font-weight: bold; 73 | margin-left: 10px; 74 | } 75 | 76 | .btn:focus { 77 | outline: 0; 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Ultimate JavaScript Projects Collection 🚀 2 | ## This is a repo containing NUMEROUS mini projects with cool UI that I'll be building everyday with Vanilla JS, without any additional framework ✌ 3 | 4 | 5 | | Project | Link | Brief Description 6 | | :------------- | :----------: | :----------: 7 | | Movie Ticket Booking | https://movie-ticket-booking.netlify.app/ | Book seat for movies 8 | | OG Video Player | https://og-video-player.netlify.app/ | Custom made video player 9 | |New Year Countdown | https://ny-countdown.netlify.app/ | Dynamic New Year Countdown 10 | |Exchange Rate Calculator | https://exchange-rate-converter.netlify.app/ | Convert one currency into another 11 | |DOM Array Methods | https://dom-methods.netlify.app/| Use DOM array methods and understand the working of the high-order functions 12 | |Modal | https://modal-menu.netlify.app/ | Modal pop-up when clicked "Sign Up" with an animated common hamburger menu 13 | | Hangman Game| https://hangman-game-vanillajs.netlify.app/ | Play Hangman: Guess the right word 14 | |GitHub Profile Finder| https://github-users-searcher.netlify.app/ | Search GitHub users and see their brief details 15 | | Movie Info | https://movie-info-search.netlify.app/ | Look at the top favourite movies now and search other movies to get the overview 16 | | Recipe Finder | https://recipe-finder-webapp.netlify.app/ | Find recipes 17 | |Beat It | https://beat-it-beats.netlify.app/ | Make quick beats with one tap 18 | |Meditate | https://meditate-relax.netlify.app/ | Meditate and relax just with 3 instructions and music 19 | |Expense Tracker| https://expense-tracker-ls.netlify.app/ | Keep a note of your expenses and income(with localstorage data update) 20 | | Music Player | https://music-player-01.netlify.app/ | Custom scalable music player 21 | | Todo Mate| https://todo-mate.netlify.app/ | Animated Todo List 22 | 23 | 24 | 25 | 26 | 27 | Inspirations include Traversy and Pop! 28 | -------------------------------------------------------------------------------- /Recipe-App/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | Recipe App 13 | 14 | 15 |
16 |

Recipe App

17 |
18 |
19 | 24 | 27 |
28 | 31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Recipe-App/script.js: -------------------------------------------------------------------------------- 1 | const search = document.getElementById('search'), 2 | submit = document.getElementById('submit'), 3 | random = document.getElementById('random'), 4 | mealsEl = document.getElementById('meals'), 5 | resultHeading = document.getElementById('result-heading'), 6 | single_mealEl = document.getElementById('single-meal'); 7 | 8 | // search meal and fetch from API 9 | let searchMeal=(e) =>{ 10 | e.preventDefault(); 11 | 12 | // Clear single meal 13 | single_mealEl.innerHTML = ''; 14 | 15 | // Get search term 16 | const term = search.value; 17 | 18 | // Check for empty submission 19 | if (term.trim()) { 20 | fetch(`https://www.themealdb.com/api/json/v1/1/search.php?s=${term}`) 21 | .then(res => res.json()) 22 | .then(data => { 23 | console.log(data); 24 | resultHeading.innerHTML = `

Search results for '${term}':

`; 25 | 26 | if (data.meals === null) { 27 | resultHeading.innerHTML = `

There are no search results. Try again!

`; 28 | } else { 29 | mealsEl.innerHTML = data.meals 30 | .map( 31 | meal => ` 32 |

33 | ${meal.strMeal} 34 |
35 |

${meal.strMeal}

36 |
37 |
38 | ` 39 | ) 40 | .join(''); 41 | } 42 | }); 43 | // Clear search text 44 | search.value = ''; 45 | } else { 46 | alert('Yo, you need to enter something!s'); 47 | } 48 | } 49 | 50 | // Fetch meal by ID 51 | function getMealById(mealID) { 52 | fetch(`https://www.themealdb.com/api/json/v1/1/lookup.php?i=${mealID}`) 53 | .then(res => res.json()) 54 | .then(data => { 55 | const meal = data.meals[0]; 56 | 57 | addMealToDOM(meal); 58 | }); 59 | } 60 | 61 | // Fetch random meal from API 62 | function getRandomMeal() { 63 | // Clear meals and heading 64 | mealsEl.innerHTML = ''; 65 | resultHeading.innerHTML = ''; 66 | 67 | fetch(`https://www.themealdb.com/api/json/v1/1/random.php`) 68 | .then(res => res.json()) 69 | .then(data => { 70 | const meal = data.meals[0]; 71 | 72 | addMealToDOM(meal); 73 | }); 74 | } 75 | 76 | // Add meal to DOM 77 | function addMealToDOM(meal) { 78 | const ingredients = []; 79 | 80 | for (let i = 1; i <= 20; i++) { 81 | if (meal[`strIngredient${i}`]) { 82 | ingredients.push( 83 | `${meal[`strIngredient${i}`]} - ${meal[`strMeasure${i}`]}` 84 | ); 85 | } else { 86 | break; 87 | } 88 | } 89 | 90 | single_mealEl.innerHTML = ` 91 |
92 |

${meal.strMeal}

93 | ${meal.strMeal} 94 |
95 | ${meal.strCategory ? `

${meal.strCategory}

` : ''} 96 | ${meal.strArea ? `

${meal.strArea}

` : ''} 97 |
98 |
99 |

${meal.strInstructions}

100 |

Ingredients

101 | 104 |
105 |
106 | `; 107 | } 108 | 109 | // Event listeners 110 | submit.addEventListener('submit', searchMeal); 111 | random.addEventListener('click', getRandomMeal); 112 | 113 | mealsEl.addEventListener('click', e => { 114 | const mealInfo = e.path.find(item => { 115 | if (item.classList) { 116 | return item.classList.contains('meal-info'); 117 | } else { 118 | return false; 119 | } 120 | }); 121 | 122 | if (mealInfo) { 123 | const mealID = mealInfo.getAttribute('data-mealid'); 124 | getMealById(mealID); 125 | } 126 | }); 127 | -------------------------------------------------------------------------------- /Recipe-App/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Mukta:wght@300&display=swap'); 2 | 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background: #c7dbd6; 9 | color: rgb(8, 7, 7); 10 | font-family: 'Mukta', 11 | sans-serif; 12 | 13 | margin-top: 3rem; 14 | } 15 | 16 | .container { 17 | margin: auto; 18 | max-width: 800px; 19 | display: flex; 20 | 21 | flex-direction: column; 22 | align-items: center; 23 | justify-content: center; 24 | text-align: center; 25 | } 26 | 27 | .flex { 28 | display: flex; 29 | } 30 | 31 | input, 32 | button { 33 | border: 1px solid #f1e6e6; 34 | border-radius: 7px 0 0 0; 35 | font-size: 21px; 36 | padding: 18px 18px; 37 | margin: 0; 38 | } 39 | 40 | input[type='text'] { 41 | width: 400px; 42 | } 43 | 44 | .search-btn { 45 | cursor: pointer; 46 | border-left: 0; 47 | border-radius: 0 0 7px 0; 48 | } 49 | 50 | .search-btn:focus, .random-btn:focus{ 51 | outline: none; 52 | } 53 | .random-btn { 54 | cursor: pointer; 55 | margin-left: 10px; 56 | border-top-right-radius: 4px; 57 | border-bottom-right-radius: 4px; 58 | } 59 | 60 | .search-btn:hover{ 61 | background-color: rgb(98, 241, 196); 62 | } 63 | 64 | .random-btn:hover{ 65 | background: rgb(155, 243, 115); 66 | } 67 | .meals { 68 | 69 | display: grid; 70 | grid-template-columns: repeat(4, 1fr); 71 | grid-gap: 20px; 72 | margin-top: 20px; 73 | } 74 | 75 | .meal { 76 | cursor: pointer; 77 | position: relative; 78 | height: 380px; 79 | width: 380px; 80 | text-align: center; 81 | } 82 | 83 | .meal img { 84 | width: 100%; 85 | height: 100%; 86 | border: 4px rgb(20, 156, 134) ; 87 | box-shadow: 1px 4px 14px rgb(20, 156, 134); 88 | border-radius: 8px; 89 | } 90 | 91 | .meal-info { 92 | position: absolute; 93 | top: 0; 94 | left: 0; 95 | height: 100%; 96 | font-size: 2rem; 97 | width: 100%; 98 | background: rgba(7, 14, 13, 0.7); 99 | display: flex; 100 | color: rgb(255, 255, 255); 101 | align-items: center; 102 | justify-content: center; 103 | transition: opacity 0.2s ease-in; 104 | opacity: 0; 105 | } 106 | 107 | .meal:hover .meal-info { 108 | opacity: 1; 109 | } 110 | 111 | .single-meal { 112 | margin: 30px auto; 113 | width: 70%; 114 | } 115 | 116 | h1{ 117 | font-size: 3rem; 118 | color: #242424; 119 | text-shadow: 1px 2px #6dd4d4; 120 | } 121 | h2{ 122 | font-size: 1.9rem; 123 | text-shadow: 1px 1px #bda2a2; 124 | } 125 | 126 | .single-meal img { 127 | width: 300px; 128 | margin: 15px; 129 | 130 | border: 4px rgb(20, 156, 134); 131 | box-shadow: 1px 4px 14px rgb(20, 156, 134); 132 | border-radius: 8px; 133 | } 134 | 135 | .single-meal-info { 136 | margin: 20px; 137 | font-weight:bold; 138 | font-size: 32px; 139 | padding: 10px; 140 | border: 2px #375475 dashed; 141 | border-radius: 51px; 142 | } 143 | 144 | .single-meal p { 145 | margin: o; 146 | 147 | letter-spacing: 0.5px; 148 | line-height: 1.5; 149 | } 150 | 151 | .single-meal ul { 152 | padding-left: 0; 153 | 154 | list-style-type: none; 155 | } 156 | 157 | .single-meal ul li { 158 | border: 1px solid #e2d6d6; 159 | border-radius: 5px; 160 | background-color: #fff; 161 | display: inline-block; 162 | color: #2d2013; 163 | font-size: 16px; 164 | font-weight: bold; 165 | padding: 5px; 166 | margin: 0 5px 5px 0; 167 | } 168 | 169 | @media (max-width: 800px) { 170 | .meals { 171 | grid-template-columns: repeat(3, 1fr); 172 | } 173 | } 174 | 175 | @media (max-width: 700px) { 176 | .meals { 177 | grid-template-columns: repeat(2, 1fr); 178 | } 179 | 180 | .meal { 181 | height: 200px; 182 | width: 200px; 183 | } 184 | } 185 | 186 | @media (max-width: 500px) { 187 | input[type='text'] { 188 | width: 100%; 189 | 190 | } 191 | 192 | .meals { 193 | grid-template-columns: 1fr; 194 | } 195 | 196 | .meal { 197 | height: 300px; 198 | width: 300px; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /Todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Todo 7 | 8 | 9 | 15 | 16 | 17 |
18 |

Todo Mate

19 |
20 | 21 |
22 | 23 | 26 | 27 |
28 | 33 |
34 |
35 | 36 |
37 | 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Todo/script.js: -------------------------------------------------------------------------------- 1 | //Select DOM 2 | const todoInput = document.querySelector(".todo-input"); 3 | const todoButton = document.querySelector(".todo-button"); 4 | const todoList = document.querySelector(".todo-list"); 5 | const filterOption = document.querySelector(".filter-todo"); 6 | 7 | //Event Listeners 8 | document.addEventListener("DOMContentLoaded", getTodos); 9 | todoButton.addEventListener("click", addTodo); 10 | todoList.addEventListener("click", deleteTodo); 11 | filterOption.addEventListener("click", filterTodo); 12 | 13 | //Functions 14 | 15 | function addTodo(e) { 16 | //Prevent natural behaviour 17 | e.preventDefault(); 18 | //Create todo div 19 | const todoDiv = document.createElement("div"); 20 | todoDiv.classList.add("todo"); 21 | //Create list 22 | const newTodo = document.createElement("li"); 23 | newTodo.innerText = todoInput.value; 24 | //Save to local - do this last 25 | //Save to local 26 | saveLocalTodos(todoInput.value); 27 | // 28 | newTodo.classList.add("todo-item"); 29 | todoDiv.appendChild(newTodo); 30 | todoInput.value = ""; 31 | //Create Completed Button 32 | const completedButton = document.createElement("button"); 33 | completedButton.innerHTML = ``; 34 | completedButton.classList.add("complete-btn"); 35 | todoDiv.appendChild(completedButton); 36 | //Create trash button 37 | const trashButton = document.createElement("button"); 38 | trashButton.innerHTML = ``; 39 | trashButton.classList.add("trash-btn"); 40 | todoDiv.appendChild(trashButton); 41 | //attach final Todo 42 | todoList.appendChild(todoDiv); 43 | } 44 | 45 | function deleteTodo(e) { 46 | const item = e.target; 47 | 48 | if (item.classList[0] === "trash-btn") { 49 | // e.target.parentElement.remove(); 50 | const todo = item.parentElement; 51 | todo.classList.add("fall"); 52 | //at the end 53 | removeLocalTodos(todo); 54 | todo.addEventListener("transitionend", (e) => { 55 | todo.remove(); 56 | }); 57 | } 58 | if (item.classList[0] === "complete-btn") { 59 | const todo = item.parentElement; 60 | todo.classList.toggle("completed"); 61 | console.log(todo); 62 | } 63 | } 64 | 65 | function filterTodo(e) { 66 | const todos = todoList.childNodes; 67 | todos.forEach(function (todo) { 68 | switch (e.target.value) { 69 | case "all": 70 | todo.style.display = "flex"; 71 | break; 72 | case "completed": 73 | if (todo.classList.contains("completed")) { 74 | todo.style.display = "flex"; 75 | } else { 76 | todo.style.display = "none"; 77 | } 78 | break; 79 | case "uncompleted": 80 | if (!todo.classList.contains("completed")) { 81 | todo.style.display = "flex"; 82 | } else { 83 | todo.style.display = "none"; 84 | } 85 | } 86 | }); 87 | } 88 | 89 | function saveLocalTodos(todo) { 90 | let todos; 91 | if (localStorage.getItem("todos") === null) { 92 | todos = []; 93 | } else { 94 | todos = JSON.parse(localStorage.getItem("todos")); 95 | } 96 | todos.push(todo); 97 | localStorage.setItem("todos", JSON.stringify(todos)); 98 | } 99 | function removeLocalTodos(todo) { 100 | let todos; 101 | if (localStorage.getItem("todos") === null) { 102 | todos = []; 103 | } else { 104 | todos = JSON.parse(localStorage.getItem("todos")); 105 | } 106 | const todoIndex = todo.children[0].innerText; 107 | todos.splice(todos.indexOf(todoIndex), 1); 108 | localStorage.setItem("todos", JSON.stringify(todos)); 109 | } 110 | 111 | function getTodos() { 112 | let todos; 113 | if (localStorage.getItem("todos") === null) { 114 | todos = []; 115 | } else { 116 | todos = JSON.parse(localStorage.getItem("todos")); 117 | } 118 | todos.forEach(function (todo) { 119 | //Create todo div 120 | const todoDiv = document.createElement("div"); 121 | todoDiv.classList.add("todo"); 122 | //Create list 123 | const newTodo = document.createElement("li"); 124 | newTodo.innerText = todo; 125 | newTodo.classList.add("todo-item"); 126 | todoDiv.appendChild(newTodo); 127 | todoInput.value = ""; 128 | //Create Completed Button 129 | const completedButton = document.createElement("button"); 130 | completedButton.innerHTML = ``; 131 | completedButton.classList.add("complete-btn"); 132 | todoDiv.appendChild(completedButton); 133 | //Create trash button 134 | const trashButton = document.createElement("button"); 135 | trashButton.innerHTML = ``; 136 | trashButton.classList.add("trash-btn"); 137 | todoDiv.appendChild(trashButton); 138 | //attach final Todo 139 | todoList.appendChild(todoDiv); 140 | }); 141 | } 142 | -------------------------------------------------------------------------------- /Todo/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Lato&display=swap"); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | background-image: linear-gradient(120deg, #74f3c2, #49a7aa); 11 | color: rgb(20, 39, 37); 12 | font-family: "Lato", sans-serif; 13 | min-height: 100vh; 14 | } 15 | 16 | header { 17 | font-size: 1.5rem; 18 | } 19 | 20 | header, 21 | form { 22 | min-height: 20vh; 23 | display: flex; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | form input { 28 | border-radius: 10px 0px 0px 0px; 29 | } 30 | form button { 31 | border-radius: 0px 0px 10px 0px; 32 | } 33 | form input, 34 | form button { 35 | padding: 0.5rem; 36 | font-size: 2rem; 37 | border: none; 38 | box-shadow: 4px 6px 4px 0.4px rgba(89, 156, 151, 0.5); 39 | background: rgba(247, 253, 252, 0.788); 40 | } 41 | 42 | .todo-input, 43 | form button:focus { 44 | outline: none; 45 | } 46 | 47 | form button { 48 | color: rgb(71, 182, 182); 49 | background: whitesmoke; 50 | cursor: pointer; 51 | } 52 | 53 | form button:hover { 54 | background: #1f5063; 55 | color: white; 56 | transition: all 0.4s ease; 57 | } 58 | 59 | .todo-container { 60 | display: flex; 61 | justify-content: center; 62 | align-items: center; 63 | } 64 | 65 | .todo-list { 66 | min-width: 30%; 67 | list-style: none; 68 | } 69 | 70 | .todo { 71 | margin: 0.5rem; 72 | background: whitesmoke; 73 | color: #161616; 74 | font-size: 1.5rem; 75 | display: flex; 76 | align-items: center; 77 | justify-content: space-between; 78 | transition: all 0.5s ease; 79 | } 80 | 81 | .todo li { 82 | flex: 1; 83 | } 84 | 85 | .trash-btn, 86 | .complete-btn { 87 | border: none; 88 | padding: 1rem; 89 | font-size: 1rem; 90 | cursor: pointer; 91 | } 92 | 93 | .complete-btn { 94 | background: rgb(105, 226, 146); 95 | } 96 | 97 | .trash-btn { 98 | background: rgb(238, 125, 125); 99 | } 100 | .todo-item { 101 | padding: 0rem 0.5rem; 102 | } 103 | 104 | .fa-trash, 105 | .fa-check { 106 | pointer-events: none; 107 | } 108 | .complete-btn:hover { 109 | background: rgb(87, 218, 87); 110 | } 111 | .trash-btn:hover { 112 | background: rgb(235, 76, 76); 113 | } 114 | 115 | .completed { 116 | text-decoration: line-through; 117 | opacity: 0.5; 118 | } 119 | 120 | .fall { 121 | transform: translateY(8rem) rotateZ(20deg); 122 | opacity: 0; 123 | } 124 | 125 | select { 126 | -webkit-appearance: none; 127 | -moz-appearance: none; 128 | appearance: none; 129 | outline: none; 130 | border: none; 131 | } 132 | 133 | .select { 134 | margin: 1rem; 135 | position: relative; 136 | overflow: hidden; 137 | box-shadow: 4px 6px 4px 0.4px rgba(89, 156, 151, 0.5); 138 | } 139 | select { 140 | color: rgb(68, 134, 160); 141 | width: 10rem; 142 | cursor: pointer; 143 | padding: 1rem; 144 | border-radius: 10px; 145 | } 146 | 147 | .select::after { 148 | content: "\25BC"; 149 | position: absolute; 150 | background: #73d4c7; 151 | top: 0; 152 | right: 0; 153 | padding: 1rem; 154 | pointer-events: none; 155 | transition: all 0.3s ease; 156 | } 157 | 158 | .select:hover::after { 159 | background: white; 160 | color: rgb(47, 206, 185); 161 | } 162 | --------------------------------------------------------------------------------