Struggling with footer and modal - javascript

I am struggling with the footer when the modal pops up. The footer doesn't get the opacity that the rest of the HTML page gets. There's anyway to fix it?
PS: It may not be clear in the snippet, so here's the image of the problem:
Codes:
/*Abre e fecha o modal*/
const Modal = {
open(){
document.querySelector('.modal-overlay').classList.toggle('active')
}
}
const transactions = [
{
id: 1,
description: 'Luz',
amount: -50000,
date: '23/01/2021'
},
{
id: 2,
description: 'Website',
amount: 500000,
date: '23/01/2021'
},
{
id: 3,
description: 'Internet',
amount: -2000,
date: '23/01/2021'
},
{
id: 3,
description: 'App',
amount: 2000,
date: '23/01/2021'
},
]
//transaçoes
const Transaction = {
entry(){
//grana que entra
},
out(){
//grana que subtrai
},
total(){
//entry - out
}
}
/* const Modal = {
open(){
document.querySelector('.modal-overlay').classList.add('active')
},
close(){
document.querySelector('.modal-overlay').classList.remove('')
}
}
*/
//criando o HTML pelo JavaScript
const DOM = {
transactionsCointainer: document.querySelector('#data-table tbody'),
addTransaction(transaction, index){
const tr = document.createElement('tr')
tr.innerHTML = DOM.innerHTMLTransaction(transaction)
DOM.transactionsCointainer.appendChild(tr)
console.log(tr.innerHTML)
},
innerHTMLTransaction(transaction) {
const CSSclass = transaction.amount> 0 ? "income" : "expense"
const amount = Utils.formatCurrency(transaction.amount)
const html =
`
<td class="description">${transaction.description}</td>
<td class="${CSSclass}">${amount}</td>
<td class="date">${transaction.date}</td>
<td>
<img src="/assets/minus.svg" alt="Remover Transação">
</td>
`
return html
}
}
const Utils = {
formatCurrency(value){
const signal = Number(value) < 0 ? "-" : ""
value = String(value).replace(/\D/g, "")
value = Number(value) / 100
value = value.toLocaleString("pt-br", {
style: "currency",
currency: "BRL"
})
return signal + value
}
}
transactions.forEach(function(transaction){
DOM.addTransaction(transaction)
})
#import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght#0,400;0,700;1,400&display=swap');
:root {
--color-dark : #363f5f;
--color-green : #2D4A22;
--color-light-green: #49aa26;
}
* {
padding: 0;
margin : 0;
border : 0;
}
body {
font-family : 'Nunito', sans-serif;
background-color: #f0f2f5;
}
html {
font-size: 93.75%;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.container {
width : min(90vw, 800px);
margin: 0 auto;
}
/* === HEADER === */
header {
background: var(--color-green);
padding : 2rem 0 10rem;
text-align: center;
}
#logo {
color : #fff;
font-weight: 100;
}
/*=== TITLES === */
h2{
margin-top : 3.2rem;
margin-bottom: 0.8rem;
color : var(--color-dark);
font-weight : normal;
}
/*=== BALANCE === */
#balance {
margin-top: -8rem;
}
#balance h2 {
color : white;
font-weight: bold;
}
/*=== CARDS === */
.card {
background : white;
padding : 1.5rem 2rem;
border-radius: 0.25rem;
margin-bottom: 2rem;
}
.card h3 {
font-weight: normal;
font-size : 1rem;
display: flex;
align-items: center;
justify-content: space-between;
}
.card p {
font-size : 2rem;
line-height: 3rem;
margin-top : 1rem;
}
.card.total {
background: var(--color-light-green);
color : white;
}
/* === TRANSAÇÕES === */
#transaction {
display: block;
overflow-x: auto;
width: 100%;
}
#data-table {
width : 100%;
border-spacing: 0 0.5rem;
}
table thead tr th:first-child,
table tbody tr td:first-child{
border-radius: 0.25rem 0 0 0.25rem;
}
table thead tr th:last-child,
table tbody tr td:last-child{
border-radius: 0 0.25rem 0.25rem 0;
}
table th {
color : #969CB3;
font-weight : normal;
padding : 1rem 2rem;
text-align : left;
background-color: white;
border-radius : 0.25rem;
font-weight : bold;
}
td.description {
color: var(--color-dark);
}
td.income {
color: #12a454;
}
td.expense {
color: rgb(228, 67, 67);
}
td.date {
color: var(--color-dark);
}
table td {
background : white;
padding : 1rem 2rem;
color : #969CB3;
font-weight: bold;
}
table tbody tr {
opacity: 0.7;
}
table tbody tr:hover{
opacity: 1;
}
button {
width: 100%;
height: 50px;
border: none;
background-color: var(--color-light-green);
color: #fff;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
border-radius: 0.25rem;
}
button:hover {
background: rgb(0, 140, 0);
}
.button-new {
color: var(--color-light-green);
text-decoration: none;
font-weight: bold;
margin-bottom: .8rem;
display: inline-block;
}
a .button {
width: 100%;
color: white;
}
.button-new:hover {
color: #06bd4c;
transition: color 700ms;
}
td img {
cursor: pointer;
}
/* === MODAL === */
.modal-overlay {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
top: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
.modal {
background: #f0f2f5;
padding: 2.4rem ;
max-width: 500px;
width: 90%;
}
/*=== MODAL FORM === */
#form {
max-width: 500px;
}
#form h2 {
margin-top: 0;
}
input {
border: none;
width: 100%;
border-radius: 0.2rem;
padding: 0.8rem;
}
.input-group {
margin-top: 0.8rem;
}
.input-group small {
opacity: .4;
font-weight: bold;
}
/*=== MODAL BUTTON === */
.input-group-actions {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 1.8rem;
}
.input-group-actions .button,
.input-group.actions button {
width: 48%;
}
.input-group-actions .button {
padding: 1rem;
width: 100%;
text-align: center;
border: 1px solid #FF4136;
border-radius: 0.25rem;
text-decoration: none;
color: white;
margin-right: 5px;
background-color: #FF4136;
text-transform: uppercase;
font-weight: bold;
}
.input-group-actions .button:hover {
background: rgb(143, 0, 0);
}
/* === FOOTER === */
footer {
text-align: center;
margin-top: 20px;
}
/* === RESPONSIVE === */
#media (min-width: 800px) {
html { font-size: 87.5%;
}
#balance {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 2rem;
}
}
#media (min-width: 992px) {
footer{
display: block;
background-color: var(--color-green);
color: #fff;
padding: 2rem 0 10rem;
bottom: 0;
position: absolute;
width: 100%;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>dev.finance$</title>
</head>
<body>
<header>
<img src="/assets/logo.svg" alt="Logo Dev Finance">
</header>
<main class="container">
<section id="balance">
<h2 class="sr-only">Balanço</h2>
<div class="card">
<h3>
<span>Entradas</span>
<img src="/assets/income.svg" alt="Imagem de Entradas">
</h3>
<p>R$ 5.000,00</p>
</div>
<div class="card">
<h3>
<span>Saídas</span>
<img src="/assets/expense.svg" alt="Imagem de Saídas">
</h3>
<p>R$ 2.000,00</p>
</div>
<div class="card total">
<h3>
<span>Total</span>
<img src="/assets/total.svg" alt="Imagem de Total">
</h3>
<p>R$ 3.000,00</p>
</div>
</section>
<section id="transaction">
<h2 class="sr-only">Transações</h2>
+ Nova Transação
<table id="data-table">
<thead>
<tr>
<th>Descrição</th>
<th>Valor</th>
<th>Data</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</section>
</main>
<div class="modal-overlay">
<div class="modal">
<div id="form">
<h2>Nova Transação</h2>
<form action="">
<div class="input-group">
<label class="sr-only" for="description">Descrição</label>
<input type="text" id="description" name="description" placeholder="Descrição">
</div>
<div class="input-group">
<label class="sr-only" for="amount">Valor</label>
<input type="number" id="amount" name="amount" placeholder="0,00" step="0.01">
<small>Usar o sinal - (negativo) para despesas e , (vírgula) para casas decimais.</small>
</div>
<div class="input-group">
<label class="sr-only" for="date">Data</label>
<input type="date" id="date" name="date">
</div>
<div class="input-group-actions">
Cancelar
<button>Salvar</button>
</div>
</div>
</div>
</div>
<footer>
<img src="/assets/logo-footer.svg" alt="Logo Dev Finance">
</footer>
<script src="scripts.js"></script>
</body>
</html>

Your modal-overlay is displaying behind your footer.
Add a z-index: 1000 to your modal-overlay rule.
.modal-overlay.active {
opacity: 1;
visibility: visible;
z-index: 1000; /* <- add this */
}

Related

How to show its subcategories when clicking on a category, and then filter products on JS?

How to make it so that when you click on a category, its subcategories (which belong to the selected category) appear, and products are filtered after clicking on the subcategory. I do not know JS.
For some reason, my code is full of errors on this site and therefore does not allow it to be published here. Even CSS-code shows errors. Apparently the site broke down. Posted the code here.
function app() {
const buttons = document.querySelectorAll('.button')
const cards = document.querySelectorAll('.card')
function filter (category, items) {
items.forEach((item) => {
const isItemFiltered = !item.classList.contains(category)
const isShowAll = category.toLowerCase() === 'all'
if (isItemFiltered && !isShowAll) {
item.classList.add('anime')
} else {
item.classList.remove('hide')
item.classList.remove('anime')
}
})
}
buttons.forEach((button) => {
button.addEventListener('click', () => {
const currentCategory = button.dataset.filter
filter(currentCategory, cards)
})
})
cards.forEach((card) => {
card.ontransitionend = function () {
if (card.classList.contains('anime')) {
card.classList.add('hide')
}
}
})
}
app()
:root {
--color-orange: #ffa728;
--color-red: #e66c6e;
--color-green: #a7d6bb;
--color-blue: #1c4961;
--color-sky: #58C9E2FF;
--color-brown: #a56e47;
}
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Courier New", Courier, monospace;
font-size: 16px;
line-height: 1.2;
background-color: #faebd7;
}
.header {
padding: 20px 0;
margin-bottom: 48px;
}
.filter {
display: flex;
justify-content: center;
max-width: 1024px;
margin: 0 auto;
}
.filter-category {
display: flex;
justify-content: center;
max-width: 1024px;
margin: 0 auto;
padding-bottom: 20px;
}
.button {
padding: 12px 24px;
margin-right: 18px;
cursor: pointer;
color: white;
text-transform: uppercase;
font-weight: bold;
border: 0;
outline: none;
border-radius: 0;
position: relative;
}
.button:last-child {
margin-right: 0;
}
.button:active {
bottom: -1px;
}
.button_type_all {
background-color: var(--color-orange);
}
.button_type_flying {
background-color: var(--color-sky);
}
.button_type_running {
background-color: var(--color-brown);
}
.button_type_cat {
background-color: var(--color-green);
}
.button_type_dog {
background-color: var(--color-red);
}
.button_type_bird {
background-color: var(--color-blue);
}
.container {
display: flex;
flex-wrap: wrap;
max-width: 1024px;
margin: 0 auto;
}
.card {
width: calc(33.3333333% - 72px);
margin: 36px;
height: 200px;
line-height: 200px;
text-align: center;
color: white;
font-weight: bold;
font-size: 48px;
overflow: hidden;
transition: 0.5s all;
}
.cat {
background-color: var(--color-green);
}
.dog {
background-color: var(--color-red);
}
.bird {
background-color: var(--color-blue);
}
.anime {
transform: scale(0);
opacity: 0;
}
.hide {
animation-name: hide;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
#keyframes hide {
0% {
visibility: visible;
height: 200px;
}
100% {
visibility: hidden;
width: 0;
height: 0;
max-width: 0;
font-size: 0;
margin: 0;
}
}
<header class="header">
<div class="filter-category">
<button class="button button_type_all" data-filter="all">All</button>
<button class="button button_type_running" data-filter="running">Running</button>
<button class="button button_type_flying" data-filter="flying">Flying</button>
</div>
<div class="filter">
<button class="button button_type_cat" data-filter="cat">Cat</button>
<button class="button button_type_dog" data-filter="dog">Dog</button>
<button class="button button_type_bird" data-filter="bird">Bird</button>
</div>
</header>
<main class="content">
<div class="container">
<div class="card cat">Cat</div>
<div class="card dog">Dog</div>
<div class="card bird">Bird</div>
<div class="card dog">Dog</div>
<div class="card cat">Cat</div>
<div class="card bird">Bird</div>
<div class="card bird">Bird</div>
<div class="card dog">Dog</div>
<div class="card cat">Cat</div>
</div>
</main>

trying to display filtered result from local storage in todo app but stuck on it

This is my first attempt at learning to work with local storage. I am trying to filter the tasks by category. So far I am able to get the tasks category-wise in console but stuck on how to display them on app. i am stuck on this, need help in understanding this.
Attaching the javascript and HTML code.
window.addEventListener('load', () => {
todos = JSON.parse(localStorage.getItem('todos')) || [];
// todosBf = JSON.parse(localStorage.getItem('todosBF')) || [];
const nameInput = document.querySelector('#name');
const newTodoForm = document.querySelector('#new-todo-form');
const username = localStorage.getItem('username') || '';
nameInput.value = username;
nameInput.addEventListener('change', e => {
localStorage.setItem('username', e.target.value);
})
newTodoForm.addEventListener('submit', e => {
e.preventDefault();
const todo = {
content: e.target.elements.content.value,
category: e.target.elements.category.value,
done: false,
createdAt: new Date().getTime()
}
const textWarning = document.querySelector('#text-warning');
const categoryWarning = document.querySelector('#category-warning');
if (todo.content == "") {
textWarning.classList.add('warning')
} else {
if (todo.category == "") {
categoryWarning.classList.add('warning')
} else {
categoryWarning.classList.remove('warning')
todos.push(todo);
localStorage.setItem('todos', JSON.stringify(todos));
e.target.reset();
displayTodos();
}
}
})
displayTodos();
});
function displayTodos() {
const todoList = document.querySelector('#todo-list');
const businessFilter = document.querySelector('#business-filter');
const personalFilter = document.querySelector('#personal-filter');
const allFilter = document.querySelector('#all-filter');
todoList.innerHTML = '';
todos.sort((a, b) => b.createdAt - a.createdAt).forEach(todo => {
const todoItem = document.createElement('div');
todoItem.classList.add('todo-item');
const label = document.createElement('label');
const input = document.createElement('input');
const span = document.createElement('span');
const content = document.createElement('div');
const actions = document.createElement('div');
const edit = document.createElement('button');
const deleteButton = document.createElement('button');
input.type = 'checkbox';
input.checked = todo.done;
span.classList.add('bubble');
if (todo.category == 'personal') {
span.classList.add('personal');
} else {
span.classList.add('business');
}
content.classList.add('todo-content');
actions.classList.add('actions');
edit.classList.add('edit');
deleteButton.classList.add('delete');
content.innerHTML = `<input type="text" value="${todo.content}" readonly>`;
edit.innerHTML = 'Edit';
deleteButton.innerHTML = 'Delete';
label.appendChild(input);
label.appendChild(span);
actions.appendChild(edit);
actions.appendChild(deleteButton);
todoItem.appendChild(label);
todoItem.appendChild(content);
todoItem.appendChild(actions);
todoList.appendChild(todoItem);
if (todo.done) {
todoItem.classList.add('done');
}
input.addEventListener('click', e => {
todo.done = e.target.checked;
localStorage.setItem('todos', JSON.stringify(todos));
if (todo.done) {
todoItem.classList.add('done');
} else {
todoItem.classList.remove('done');
}
displayTodos();
})
edit.addEventListener('click', e => {
const input = content.querySelector('input');
input.removeAttribute('readonly');
input.focus();
input.addEventListener('blur', e => {
input.setAttribute('readonly', true);
todo.content = e.target.value;
localStorage.setItem('todos', JSON.stringify(todos));
displayTodos();
})
})
deleteButton.addEventListener('click', e => {
todos = todos.filter(t => t != todo);
localStorage.setItem('todos', JSON.stringify(todos));
displayTodos();
})
});
businessFilter.addEventListener('click', e => {
// todosBF = todos.filter( todo => todo.category == 'business');
// localStorage.setItem('todosBF', JSON.stringify(todosBF));
JSON.parse(localStorage.getItem('todos')).filter( t => t.category == 'business');
});
};
:root {
--primary: #EA40A4;
--business: #3A82EE;
--personal: var(--primary);
--light: #EEE;
--grey: #888;
--dark: #313154;
--danger: #ff5b57;
--shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
--business-glow: 0px 0px 4px rgba(58, 130, 238, 0.75);
--personal-glow: 0px 0px 4px rgb(234, 64, 164, 0.75);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'montserrat', sans-serif;
}
input:not([type="radio"]):not([type="checkbox"]), button {
appearance: none;
border: none;
outline: none;
background: none;
cursor: initial;
}
body {
background: var(--light);
color: var(--dark);
}
section {
margin-top: 2rem;
margin-bottom: 2rem;
padding-left: 1.5rem;
padding-right: 1.5rem;
}
h3 {
color: var(--dark);
font-size: 1rem;
font-weight: 400;
margin-bottom: 0.5rem;
}
h4 {
color: var(--grey);
font-size: 0.875rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.greeting .title {
display: flex;
}
.greeting .title input{
margin-left: 0.5rem;
flex: 1 1 0%;
min-width: 0;
}
.greeting .title,
.greeting .title input {
color: var(--dark);
font-size: 1.5rem;
font-weight: 700;
}
.create-todo input[type="text"] {
display: block;
width: 100%;
font-size: 1.125rem;
padding: 1rem 1.5rem;
color: var(--dark);
background-color: #FFF;
border-radius: 0.5rem;
box-shadow: var(--shadow);
margin-bottom: 1.5rem;
}
.create-todo .options {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 1rem;
margin-bottom: 1.5rem;
}
.create-todo .options label {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.5rem;
background-color: #FFF;
border-radius: 0.5rem;
box-shadow: var(--shadow);
cursor: pointer;
}
input[type="radio"],
input[type="checkbox"] {
display: none;
}
.bubble {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border-radius: 50%;
border: 2px solid var(--business);
box-shadow: var(--business-glow);
}
.bubble.personal {
border-color: var(--personal);
box-shadow: var(--personal-glow);
}
.bubble::after {
content: "";
display: block;
opacity: 0;
width: 0px;
height: 0px;
background-color: var(--business);
box-shadow: var(--business-glow);
border-radius: 50%;
transition: 0.2s ease-in-out;
}
.bubble.personal::after {
background-color: var(--personal);
box-shadow: var(--personal-glow);
}
input:checked ~ .bubble::after {
width: 10px;
height: 10px;
opacity: 1;
}
.create-todo .options label div {
color: var(--dark);
font-size: 1.125rem;
margin-top: 1rem;
}
.create-todo input[type="submit"] {
display: block;
width: 100%;
font-size: 1.125rem;
padding: 1rem 1.5rem;
color: #FFF;
background-color: var(--primary);
border-radius: 0.5rem;
box-shadow: 0.5rem;
cursor: pointer;
transition: 0.2s ease-in-out;
}
.create-todo input[type="submit"]:hover {
opacity: 0.75;
}
.todo-list .todo-item {
display: flex;
align-items: center;
background-color: #FFF;
padding: 1rem;
border-radius: 0.5rem;
box-shadow: var(--shadow);
margin-bottom: 1rem;
}
.todo-item label {
display: block;
margin-right: 1rem;
cursor: pointer;
}
.todo-item .todo-content {
flex: 1 1 0%;
}
.todo-item .todo-content input {
color: var(--dark);
font-size: 1.125rem;
}
.todo-item .actions {
display: flex;
align-items: center;
}
.todo-item .actions button {
display: block;
padding: 0.5rem;
border-radius: 0.25rem;
color: #FFF;
cursor: pointer;
transition: 0.2s ease-in-out;
}
.todo-item .actions button:hover {
opacity: 0.75;
}
.todo-item .actions .edit {
margin-right: 0.5rem;
background-color: var(--primary);
}
.todo-item .actions .delete {
background-color: var(--danger);
}
.todo-item.done .todo-content input {
text-decoration: line-through;
color: var(--grey);
}
.empty-warning {
color: red;
opacity: 70%;
position: relative;
bottom: 20px;
display: none;
}
.category-warning {
color: red;
opacity: 70%;
position: relative;
bottom: 10px;
display: none;
}
.warning {
display: block;
}
.filter-feature input[type="button"] {
padding: 0 .5rem;
cursor: pointer;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght#0,400;0,700;0,900;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="./style.css">
<title>TODO List App</title>
</head>
<body>
<main class="app">
<section class="greeting">
<h2 class="title">
What's up, <input type="text" id="name" placeholder="Name Here">
</h2>
</section>
<section class="create-todo">
<h3>Create a TODO</h3>
<form id="new-todo-form">
<h4>What's on your todo list?</h4>
<input
type="text"
name="content"
id="content"
placeholder="e.g. make a video" />
<h4 class="empty-warning" id="text-warning">Please Enter Something</h4>
<h4>Pick a category</h4>
<div class="options">
<label>
<input
type="radio"
name="category"
id="category1"
value="business" />
<span class="bubble business"></span>
<div>Business</div>
</label>
<label>
<input
type="radio"
name="category"
id="category2"
value="personal" />
<span class="bubble personal"></span>
<div>Personal</div>
</label>
</div>
<h4 class="category-warning" id="category-warning">Select a category for your TODO</h4>
<input type="submit" value="Add todo">
</form>
</section>
<section class="todo-list">
<h3>TODO LIST</h3>
<div class="filter-feature" id="filter-feature">
<h3 class="filter-title">
Filter by:
<input type="button" value="All" id="all-filter">
<input type="button" value="Business" id="business-filter">
<input type="button" value="Personal" id="personal-filter">
</h3>
</div>
<div class="list" id="todo-list">
<!-- <div class="todo-item">
<label>
<input type="checkbox" />
<span class="bubble business"></span>
</label>
<div class="todo-content">
<input type="text" value="Make a video" readonly>
</div>
<div class="actions">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</div>
</div>
<div class="todo-item">
<label>
<input type="checkbox" />
<span class="bubble personal"></span>
</label>
<div class="todo-content">
<input type="text" value="Get milk" readonly>
</div>
<div class="actions">
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</div>
</div> -->
</div>
</section>
</main>
<script src="./app.js"></script>
</body>
</html>

I am having a problem with Query selectors for this project website

So I am learning web dev, and I am a beginner. I have learned a tiny bit about DOM manipulation and I am facing a small issue with a click event.
The HTML CSS and JS code in codepen
Please click on the pizza image. When you click on it, the box shadow should remain even after you do not hover over the pizza and the gray link bar bellow is now yellow even when you don't hover over it. Click back on it and it returns to normal, neat!
Please now click on the pavlova (the sweet pinkish dessert). It doesn't work even though it shares the exact same css classes and everything when it comes to style.
I hope I have described my problem properly. If anything is not clear I will explain more. I have been on this for a while and I really don't know how to fix it. I will include the code here as well but everything is on code pen above, whichever is preferred.
const theFoodImg = document.querySelector('.food-img');
const recipeLink = document.querySelector('.recipe-link');
const linkIcon = document.querySelector('.fa-link');
const pinTopBar = document.querySelector('.fa-thumbtack');
const topBar = document.querySelector('#top-bar');
const pinColor = document.querySelector('.fa-thumbtack');
theFoodImg.addEventListener('click', function() {
if (theFoodImg.classList.contains('active')) {
theFoodImg.classList.remove('active');
theFoodImg.classList.remove('food-hover');
theFoodImg.classList.add('food-img');
recipeLink.classList.add('recipe-link');
recipeLink.classList.remove('click');
linkIcon.classList.add('white-link')
linkIcon.classList.remove('blue-link')
} else {
theFoodImg.classList.remove('food-img');
theFoodImg.classList.add('active');
recipeLink.classList.remove('recipe-link');
recipeLink.classList.add('click');
linkIcon.classList.remove('white-link')
linkIcon.classList.add('blue-link')
}
})
theFoodImg.addEventListener('mouseenter', function() {
if (theFoodImg.classList.contains('active') !== true) {
theFoodImg.classList.add('food-hover');
}
})
if (topBar.classList.contains('fix')) {
pinColor.style.color = 'goldenrod';
}
pinTopBar.addEventListener('click', function() {
if (topBar.classList.contains('fix') !== true) {
topBar.classList.add('fix');
pinColor.style.color = 'goldenrod';
} else {
topBar.classList.remove('fix');
pinColor.style.color = 'black';
}
})
/* css reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
text-decoration: none;
}
body {
margin: 0;
padding: 0;
}
a {
color: black;
text-decoration: none;
}
hr {
width: 80%;
margin: 0 auto;
background-color: black;
box-shadow: 0 0 15px gold;
}
/* banner and title styles */
div#banner {
background: url(https://i.ibb.co/MgBrNdY/background-img.jpg);
box-shadow: inset 0 0 0 9000em rgba(68, 68, 68, 0.5);
background-size: cover;
height: 50vh;
/* change later for media queries */
}
/* title style */
h1#large-screen-title {
color: goldenrod;
text-align: center;
padding: 0.5em;
font-size: 4em;
}
div#top-bar {
background-color: rgb(255, 250, 234);
height: min-content;
}
.fix {
position: fixed;
height: 15%;
right: 0;
left: 0;
top: 0;
box-shadow: 0 0 20px goldenrod;
}
img#odin-logo {
height: 5em;
}
i.fa-thumbtack {
float: right;
padding: 1em;
}
i.fa-thumbtack:hover {
cursor: pointer;
}
#media only screen and (min-width: 700px) {
div#banner {
height: 80vh;
}
h1#title-index {
height: 60vh;
color: transparent;
border: 0px solid white;
}
div#top-bar {
text-align: center;
}
}
/* recipe card styles */
div#recipe-card-container {
padding-top: 5em;
padding-left: 0.5em;
padding-right: 0.5em;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
align-items: center;
gap: 2em;
}
/*each recipe card */
div#recipe-card-container>div.each-recipe {
display: grid;
gap: 2em;
margin-bottom: 5em;
justify-content: center;
}
div#recipe-card-container div.recipe-img {
/* background-color: red; */
width: 100%;
height: 50vh;
border-radius: 3px;
transition: 450ms;
}
/*recipe link within each card */
div.recipe-link {
background-color: lightgray;
text-align: center;
padding-top: 1em;
padding: 0.5em;
transition: 450ms;
border-radius: 0.3em;
}
div.recipe-link:hover {
background-color: #eece1a;
transition: 450ms;
}
/* when clicked add this style */
.click {
background-color: #eece1a;
text-align: center;
padding-top: 1em;
padding: 0.5em;
border-radius: 0.3em;
transition: 450ms;
width: 100%;
margin: 0 auto;
}
/**/
i.fa-link {
float: left;
}
div.recipe-link:hover>i.fa-link {
color: rgb(0, 0, 255, 0.5);
}
/*when clicked, target i.fa-link color */
.white-link {
color: white;
}
.blue-link {
color: rgb(0, 0, 255, 0.5);
}
/* food image style on card */
.food-img {
height: 100%;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
img.food-img {
width: 100%;
}
img.food-hover:hover,
.active {
box-shadow: 0 0 20px rgb(189, 80, 12);
height: 105%;
object-fit: cover;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
/*grey bar with copyright*/
div.copy {
background-color: rgba(0, 0, 0, 0.54);
margin-top: 2em;
padding: 2em;
color: white;
text-align: center;
}
#media only screen and (min-width: 1020px) {
div#recipe-card-container {
padding-left: 0;
padding-right: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
gap: 2em;
margin-top: 2em;
box-shadow: inset 0 500px rgb(85, 63, 63);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="../style.css" />
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Odin Recipes</title>
</head>
<body>
<div id="banner">
<div id="top-bar" class="fix">
<img src="https://i.ibb.co/7nhgfNJ/odin-logo.png" alt="" id="odin-logo" />
<i class="fa-solid fa-thumbtack"></i>
</div>
</div>
<br />
<br />
<hr />
<h1 id="large-screen-title">Odin Recipes</h1>
<br /><br />
<hr />
<div id="recipe-card-container">
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/mDCCZTW/pizza.jpg" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/pizza.html">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pizza Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/5cQCFWP/pavlova.png" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/pavlova.html">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="/recipes/images/" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova Recipe
</div>
</a>
</div>
</div>
<div class="copy">Copyright © 2022</div>
<script src="https://kit.fontawesome.com/fb94170dc7.js" crossorigin="anonymous"></script>
<script src="app.js"></script>
</body>
</html>
Check out the below snippet. i have updated theFoodImg variable to theFoodImgs and leveraged querySelectorAll to get a node list of all the .food-img class elements.
Then use a foreach loop on the nodelist to loop it and add your listeners.
You may want to update more of your variables from querySelector to querySelectorAll. I have done this one to get you headed down the correct path.
**Edit added a recipeLink class. cant key off of a class in the selector that is being added and removed. The snippet should be in full working order now.
const theFoodImgs = document.querySelectorAll('.food-img'),
pinTopBar = document.querySelector('.fa-thumbtack'),
topBar = document.querySelector('#top-bar'),
pinColor = document.querySelector('.fa-thumbtack');
let recipeLink, linkIcon;
theFoodImgs.forEach(function (el) {
el.addEventListener('click', function() {
recipeLink = this.parentNode.parentNode.querySelector('.recipeLink');
linkIcon = this.parentNode.parentNode.querySelector('.fa-link');
if(this.classList.contains('active')){
this.classList.remove('active');
this.classList.remove('food-hover');
this.classList.add('food-img');
recipeLink.classList.add('recipe-link');
recipeLink.classList.remove('click');
linkIcon.classList.add('white-link')
linkIcon.classList.remove('blue-link')
} else {
this.classList.remove('food-img');
this.classList.add('active');
recipeLink.classList.remove('recipe-link');
recipeLink.classList.add('click');
linkIcon.classList.remove('white-link')
linkIcon.classList.add('blue-link')
}
});
el.addEventListener('mouseenter', function(){
if (el.classList.contains('active') !== true) {
el.classList.add('food-hover');
}
})
});
if(topBar.classList.contains('fix')) {
pinColor.style.color = 'goldenrod';
}
pinTopBar.addEventListener('click', function() {
if(topBar.classList.contains('fix') !== true) {
topBar.classList.add('fix');
pinColor.style.color = 'goldenrod';
}
else {
topBar.classList.remove('fix');
pinColor.style.color = 'black';
}
})
/* css reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
text-decoration: none;
}
body {
margin: 0;
padding: 0;
}
a {
color: black;
text-decoration: none;
}
hr {
width: 80%;
margin: 0 auto;
background-color: black;
box-shadow: 0 0 15px gold;
}
/* banner and title styles */
div#banner {
background: url(https://i.ibb.co/MgBrNdY/background-img.jpg);
box-shadow: inset 0 0 0 9000em rgba(68, 68, 68, 0.5);
background-size: cover;
height: 50vh; /* change later for media queries */
}
/* title style */
h1#large-screen-title {
color: goldenrod;
text-align: center;
padding: 0.5em;
font-size: 4em;
}
div#top-bar {
background-color: rgb(255, 250, 234);
height: min-content;
}
.fix {
position: fixed;
height: 15%;
right: 0;
left: 0;
top: 0;
box-shadow: 0 0 20px goldenrod;
}
img#odin-logo {
height: 5em;
}
i.fa-thumbtack {
float: right;
padding: 1em;
}
i.fa-thumbtack:hover {
cursor: pointer;
}
#media only screen and (min-width: 700px) {
div#banner {
height: 80vh;
}
h1#title-index {
height: 60vh;
color: transparent;
border: 0px solid white;
}
div#top-bar {
text-align: center;
}
}
/* recipe card styles */
div#recipe-card-container {
padding-top: 5em;
padding-left: 0.5em;
padding-right: 0.5em;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
align-items: center;
gap: 2em;
}
/*each recipe card */
div#recipe-card-container > div.each-recipe {
display: grid;
gap: 2em;
margin-bottom: 5em;
justify-content: center;
}
div#recipe-card-container div.recipe-img {
/* background-color: red; */
width: 100%;
height: 50vh;
border-radius: 3px;
transition: 450ms;
}
/*recipe link within each card */
div.recipe-link {
background-color: lightgray;
text-align: center;
padding-top: 1em;
padding: 0.5em;
transition: 450ms;
border-radius: 0.3em;
}
div.recipe-link:hover {
background-color: #eece1a;
transition: 450ms;
}
/* when clicked add this style */
.click {
background-color: #eece1a;
text-align: center;
padding-top: 1em;
padding: 0.5em;
border-radius: 0.3em;
transition: 450ms;
width: 100%;
margin: 0 auto;
}
/**/
i.fa-link {
float: left;
}
div.recipe-link:hover > i.fa-link {
color: rgb(0, 0, 255, 0.5);
}
/*when clicked, target i.fa-link color */
.white-link {
color: white;
}
.blue-link {
color: rgb(0, 0, 255, 0.5);
}
/* food image style on card */
.food-img {
height: 100%;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
img.food-img {
width: 100%;
}
img.food-hover:hover,
.active {
box-shadow: 0 0 20px rgb(189, 80, 12);
height: 105%;
object-fit: cover;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
/*grey bar with copyright*/
div.copy {
background-color: rgba(0, 0, 0, 0.54);
margin-top: 2em;
padding: 2em;
color: white;
text-align: center;
}
#media only screen and (min-width: 1020px) {
div#recipe-card-container {
padding-left: 0;
padding-right: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
gap: 2em;
margin-top: 2em;
box-shadow: inset 0 500px rgb(85, 63, 63);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="../style.css" />
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Odin Recipes</title>
</head>
<body>
<div id="banner">
<div id="top-bar" class="fix">
<a href="https://www.theodinproject.com/"
><img src="https://i.ibb.co/7nhgfNJ/odin-logo.png" alt="" id="odin-logo"
/></a>
<i class="fa-solid fa-thumbtack"></i>
</div>
</div>
<br />
<br />
<hr />
<h1 id="large-screen-title">Odin Recipes</h1>
<br /><br />
<hr />
<div id="recipe-card-container">
<div class="each-recipe">
<div class="recipe-img">
<img
src="https://i.ibb.co/mDCCZTW/pizza.jpg"
alt=""
class="food-img food-hover"
/>
</div>
<a href="/recipes/pizza.html">
<div class="recipe-link recipeLink">
<i class="fa-solid fa-link white-link"></i>Click here for Pizza
Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/5cQCFWP/pavlova.png" alt="" class="food-img food-hover"/>
</div>
<a href="/recipes/pavlova.html">
<div class="recipe-link recipeLink">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img
src="/recipes/images/"
alt=""
class="food-img food-hover"
/>
</div>
<a href="/recipes/">
<div class="recipe-link recipeLink">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova
Recipe
</div>
</a>
</div>
</div>
<div class="copy">Copyright © 2022</div>
<script
src="https://kit.fontawesome.com/fb94170dc7.js"
crossorigin="anonymous"
></script>
<script src="app.js"></script>
</body>
</html>
I simplified the process to not query ANY loops. Instead I'm assigning the event handler to the parent of the recipes. Then I look for the active element and REMOVE the active class from the recipe itself. Instead of adding/removing classes from each element, I simply add an active class to the recipe parent and use CSS to modify the children of the active class.
const recipes = document.querySelector("#recipe-card-container")
recipes.addEventListener("click", function(el) {
let target = el.target;
if (target.className.indexOf("food-img") > -1) {
let active = document.querySelector(".each-recipe.active");
if (active) {
active.classList.remove("active");
}
target.parentNode.parentNode.classList.add("active");
}
});
/* css reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
text-decoration: none;
}
body {
margin: 0;
padding: 0;
}
a {
color: black;
text-decoration: none;
}
hr {
width: 80%;
margin: 0 auto;
background-color: black;
box-shadow: 0 0 15px gold;
}
/* banner and title styles */
div#banner {
background: url(https://i.ibb.co/MgBrNdY/background-img.jpg);
box-shadow: inset 0 0 0 9000em rgba(68, 68, 68, 0.5);
background-size: cover;
height: 50vh;
/* change later for media queries */
}
/* title style */
h1#large-screen-title {
color: goldenrod;
text-align: center;
padding: 0.5em;
font-size: 4em;
}
div#top-bar {
background-color: rgb(255, 250, 234);
height: min-content;
}
.fix {
position: fixed;
height: 15%;
right: 0;
left: 0;
top: 0;
box-shadow: 0 0 20px goldenrod;
}
img#odin-logo {
height: 5em;
}
i.fa-thumbtack {
float: right;
padding: 1em;
}
i.fa-thumbtack:hover {
cursor: pointer;
}
#media only screen and (min-width: 700px) {
div#banner {
height: 80vh;
}
h1#title-index {
height: 60vh;
color: transparent;
border: 0px solid white;
}
div#top-bar {
text-align: center;
}
}
/* recipe card styles */
div#recipe-card-container {
padding-top: 5em;
padding-left: 0.5em;
padding-right: 0.5em;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
align-items: center;
gap: 2em;
}
/*each recipe card */
div#recipe-card-container>div.each-recipe {
display: grid;
gap: 2em;
margin-bottom: 5em;
justify-content: center;
}
div#recipe-card-container div.recipe-img {
/* background-color: red; */
width: 100%;
height: 50vh;
border-radius: 3px;
transition: 450ms;
}
/*recipe link within each card */
div.recipe-link {
background-color: lightgray;
text-align: center;
padding-top: 1em;
padding: 0.5em;
transition: 450ms;
border-radius: 0.3em;
}
div.recipe-link:hover {
background-color: #eece1a;
transition: 450ms;
}
/* when clicked add this style */
.active .recipe-link {
background-color: #eece1a;
text-align: center;
padding-top: 1em;
padding: 0.5em;
border-radius: 0.3em;
transition: 450ms;
width: 100%;
margin: 0 auto;
}
/**/
i.fa-link {
float: left;
}
div.recipe-link:hover>i.fa-link {
color: rgb(0, 0, 255, 0.5);
}
/*when clicked, target i.fa-link color */
.recipe-link i {
color: white;
}
.each-recipe.active i {
color: rgb(0, 0, 255, 0.5);
}
/* food image style on card */
.food-img {
height: 100%;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
img.food-img {
width: 100%;
}
img.food-hover:hover,
.each-recipe.active img {
box-shadow: 0 0 20px rgb(189, 80, 12);
height: 105%;
object-fit: cover;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
/*grey bar with copyright*/
div.copy {
background-color: rgba(0, 0, 0, 0.54);
margin-top: 2em;
padding: 2em;
color: white;
text-align: center;
}
#media only screen and (min-width: 1020px) {
div#recipe-card-container {
padding-left: 0;
padding-right: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
gap: 2em;
margin-top: 2em;
box-shadow: inset 0 500px rgb(85, 63, 63);
}
}
<div id="recipe-card-container">
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/mDCCZTW/pizza.jpg" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/pizza.html">
<div class="recipe-link">
<i class="fa-solid fa-link"></i>Click here for Pizza Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/5cQCFWP/pavlova.png" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/pavlova.html">
<div class="recipe-link">
<i class="fa-solid fa-link"></i>Click here for Pavlova Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="/recipes/images/" alt="" class="food-img food-hover" />
</div>
<a href="/recipes/">
<div class="recipe-link">
<i class="fa-solid fa-link"></i>Click here for Pavlova Recipe
</div>
</a>
</div>
</div>
<div class="copy">Copyright © 2022</div>
<script src="https://kit.fontawesome.com/fb94170dc7.js" crossorigin="anonymous"></script>
It finally worked!
// const theFoodImg = document.querySelector('.food-img');
// const recipeLink = document.querySelector('.recipe-link');
// const linkIcon = document.querySelector('.fa-link');
const pinTopBar = document.querySelector('.fa-thumbtack');
const topBar = document.querySelector('#top-bar');
const pinColor = document.querySelector('.fa-thumbtack');
// theFoodImg.addEventListener('click', function() {
// if(theFoodImg.classList.contains('active')){
// theFoodImg.classList.remove('active');
// theFoodImg.classList.remove('food-hover');
// theFoodImg.classList.add('food-img');
// recipeLink.classList.add('recipe-link');
// recipeLink.classList.remove('click');
// linkIcon.classList.add('white-link')
// linkIcon.classList.remove('blue-link')
// } else {
// theFoodImg.classList.remove('food-img');
// theFoodImg.classList.add('active');
// recipeLink.classList.remove('recipe-link');
// recipeLink.classList.add('click');
// linkIcon.classList.remove('white-link');
// linkIcon.classList.add('blue-link');
// }
// })
// theFoodImg.addEventListener('mouseenter', function(){
// if (theFoodImg.classList.contains('active') !== true) {
// theFoodImg.classList.add('food-hover');
// }
// })
if(topBar.classList.contains('fix')) {
pinColor.style.color = 'goldenrod';
}
pinTopBar.addEventListener('click', function() {
if(topBar.classList.contains('fix') !== true) {
topBar.classList.add('fix');
pinColor.style.color = 'goldenrod';
}
else {
topBar.classList.remove('fix');
pinColor.style.color = 'black';
}
})
const recipeContainer = document.querySelector('div#recipe-card-container');
const linkIcon = document.querySelectorAll('.fa-link');
recipeContainer.addEventListener('click',function(event){
if(event.target.classList.contains('food-img') || event.target.classList.contains('food-hover')){
if(event.target.classList.contains('active')==false) {
event.target.classList.remove('food-img');
event.target.classList.add('active');
const recipeImg = event.target.parentElement;
const aTag = recipeImg.nextElementSibling;
const recipeLink = aTag.firstElementChild;
const linkIcon = recipeLink.firstElementChild;
recipeLink.classList.remove('recipe-link');
recipeLink.classList.add('click');
linkIcon.classList.remove('white-link');
linkIcon.classList.add('blue-link');
if(!event.target.classList.contains('food-hover')){
event.target.classList.add('food-hover');
}
} else {
event.target.classList.remove('active');
event.target.classList.remove('food-hover');
event.target.classList.add('food-img');
const recipeImg = event.target.parentElement;
const aTag = recipeImg.nextElementSibling;
const recipeLink = aTag.firstElementChild;
const linkIcon = recipeLink.firstElementChild;
linkIcon.classList.add('white-link');
linkIcon.classList.remove('blue-link');
recipeLink.classList.add('recipe-link');
recipeLink.classList.remove('click');
}
}
})
/* css reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
text-decoration: none;
}
body {
margin: 0;
padding: 0;
}
a {
color: black;
text-decoration: none;
}
hr {
width: 80%;
margin: 0 auto;
background-color: black;
box-shadow: 0 0 15px gold;
}
/* banner and title styles */
div#banner {
background: url(https://i.ibb.co/MgBrNdY/background-img.jpg);
box-shadow: inset 0 0 0 9000em rgba(68, 68, 68, 0.5);
background-size: cover;
height: 50vh; /* change later for media queries */
}
/* title style */
h1#large-screen-title {
color: goldenrod;
text-align: center;
padding: 0.5em;
font-size: 4em;
}
div#top-bar {
background-color: rgb(255, 250, 234);
height: min-content;
}
.fix {
position: fixed;
height: 15%;
right: 0;
left: 0;
top: 0;
box-shadow: 0 0 20px goldenrod;
}
img#odin-logo {
height: 5em;
}
i.fa-thumbtack {
float: right;
padding: 1em;
}
i.fa-thumbtack:hover {
cursor: pointer;
}
#media only screen and (min-width: 700px) {
div#banner {
height: 80vh;
}
h1#title-index {
height: 60vh;
color: transparent;
border: 0px solid white;
}
div#top-bar {
text-align: center;
}
}
/* recipe card styles */
div#recipe-card-container {
padding-top: 5em;
padding-left: 0.5em;
padding-right: 0.5em;
display: grid;
grid-template-columns: 1fr;
justify-content: center;
align-items: center;
gap: 2em;
}
/*each recipe card */
div#recipe-card-container > div.each-recipe {
display: grid;
gap: 2em;
margin-bottom: 5em;
justify-content: center;
}
div#recipe-card-container div.recipe-img {
/* background-color: red; */
width: 100%;
height: 45vh;
border-radius: 3px;
transition: 450ms;
}
/*recipe link within each card */
div.recipe-link {
background-color: lightgray;
text-align: center;
padding-top: 1em;
padding: 0.5em;
transition: 450ms;
border-radius: 0.3em;
width: 100%;
margin: 0 auto;
}
div.recipe-link:hover {
background-color: #eece1a;
transition: 450ms;
}
/* when clicked add this style */
.click {
background-color: #eece1a;
text-align: center;
padding-top: 1em;
padding: 0.5em;
border-radius: 0.3em;
transition: 450ms;
width: 100%;
margin: 0 auto;
}
/**/
i.fa-link {
float: left;
}
div.recipe-link:hover > i.fa-link {
color: rgb(0, 0, 255, 0.5);
}
/*when clicked, target i.fa-link color */
.white-link {
color: white;
}
.blue-link {
color: rgb(0, 0, 255, 0.5);
}
/* food image style on card */
.food-img {
height: 100%;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
img.food-img {
width: 100%;
}
img.food-hover {
box-shadow: 0 0 20px #eee;
}
img.food-img:hover,
.active {
box-shadow: 0 0 20px rgb(189, 80, 12);
height: 105%;
object-fit: cover;
border-radius: 50%;
border: 4px solid rgba(189, 80, 12, 0.637);
transition: 450ms;
cursor: pointer;
}
/*grey bar with copyright*/
div.copy {
background-color: rgba(0, 0, 0, 0.54);
margin-top: 30vh;
padding: 2em;
color: white;
text-align: center;
}
#media only screen and (min-width: 1020px) {
div#recipe-card-container {
padding-left: 0;
padding-right: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
align-items: center;
gap: 2em;
margin-top: 2em;
box-shadow: inset 0 700px rgb(85, 63, 63);
}
}
#media only screen and (max-width: 720px) {
div#recipe-card-container div.recipe-img {
width: 100%;
height: 30vh;
border-radius: 3px;
object-fit: cover;
}
.food-img {
height: 30vh;
border-radius: 20px;
border: 4px solid rgba(189, 80, 12, 0.637);
cursor: pointer;
object-fit: cover;
}
img.food-hover:hover,
.active {
box-shadow: 0 0 20px rgb(189, 80, 12);
height: 32vh;
object-fit: cover;
border-radius: 20px;
border: 4px solid rgba(189, 80, 12, 0.637);
cursor: pointer;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="../style.css" />
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Odin Recipes</title>
</head>
<body>
<div id="banner">
<div id="top-bar" class="fix">
<a href="https://www.theodinproject.com/"
><img src="https://i.ibb.co/7nhgfNJ/odin-logo.png" alt="" id="odin-logo"
/></a>
<i class="fa-solid fa-thumbtack"></i>
</div>
</div>
<br />
<br />
<hr />
<h1 id="large-screen-title">Odin Recipes</h1>
<br /><br />
<hr />
<div id="recipe-card-container">
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/mDCCZTW/pizza.jpg" alt="" class="food-img" />
</div>
<a href="/recipes/pizza.html">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pizza
Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="https://i.ibb.co/5cQCFWP/pavlova.png" alt="" class="food-img" />
</div>
<a href="/recipes/pavlova.html">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova
Recipe
</div>
</a>
</div>
<div class="each-recipe">
<div class="recipe-img">
<img src="/recipes/images/" alt="" class="food-img" />
</div>
<a href="/recipes/">
<div class="recipe-link">
<i class="fa-solid fa-link white-link"></i>Click here for Pavlova
Recipe
</div>
</a>
</div>
</div>
<div class="copy">Copyright © 2022</div>
<script
src="https://kit.fontawesome.com/fb94170dc7.js"
crossorigin="anonymous"
></script>
<script src="app.js"></script>
</body>
</html>

mouseover and mouseout misbehaves when Vue JS transition component is used

I am creating a popup menu as shown below
const menuItem = {
props: ['name', 'val'],
data() {
return {
showChild: false
}
},
template: /*html */ `
<div class="nav-item" #mouseover="showChild=true" #mouseout="showChild=false">
<span v-if="typeof val === 'string' || val instanceof String">
<a :href="val" target="_blank" rel="noopener noreferrer">{{name}}</a>
</span>
<div v-else>
{{name}}
<ul class="popup" v-show="showChild">
<li v-for="(link, name) in val">
<a :href="link" target="_blank" rel="noopener noreferrer">{{name}}</a>
</li>
</ul>
</div>
</div>
`
}
const app = Vue.createApp({
components: {
menuItem
},
data() {
return {
menu: {
'Home': '#',
'Services': {
'Software Development': 'https://www.upwork.com/signup/create-account/client_contact_freelancer?ciphertext=~0142999d8b15001517&BYOC',
'Business Training & Frenchise': 'https://www.badabusiness.com/dd/BIMK003866',
'Organic Marketing Training & Affiliate Program': 'https://leads-arc.web.app/'
},
'Our Apps': {
'All': 'https://play.google.com/store/apps/collection/cluster?clp=igM4ChkKEzUwMDkwNjA5NzAwNjg3NTk4ODIQCBgDEhkKEzUwMDkwNjA5NzAwNjg3NTk4ODIQCBgDGAA%3D:S:ANO1ljIhW_g&gsr=CjuKAzgKGQoTNTAwOTA2MDk3MDA2ODc1OTg4MhAIGAMSGQoTNTAwOTA2MDk3MDA2ODc1OTg4MhAIGAMYAA%3D%3D:S:ANO1ljJmSZ8',
'Featured': 'https://play.google.com/store/apps/dev?id=5009060970068759882',
'Srila Prabhupada Vani': 'https://play.google.com/store/apps/details?id=com.mayank.srilaprabhupadavani',
'ChatEasy - Easy Messaging': 'https://play.google.com/store/apps/details?id=c.kapps.easymessage.free'
},
'Blogs': 'https://mayank-1513.medium.com/',
'Contact Us': 'https://mayank-chaudhari.web.app/',
},
}
}
})
app.mount('#app');
* {
max-width: 1600px;
margin: auto;
transition: 0.2s all cubic-bezier(0.65, 0.05, 0.36, 1);
color: #2c3e50;
cursor: unset;
box-sizing: border-box;
}
body,
html,
#app {
margin: 0;
padding: 0;
font-family: Avenir, Helvetica, Arial, sans-serif;
max-width: 100%;
}
nav {
display: flex;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
background: transparent;
align-items: center;
align-content: center;
justify-content: center;
}
nav.tr {
background: white;
box-shadow: #5555 0 0 0 2px;
height: 60px;
}
.nav {
display: flex;
align-items: center;
width: 100%;
padding: 15px;
height: 50px;
}
.nav-item {
display: inline-block;
position: relative;
padding: 10px 0;
margin: 20px;
font-weight: bold;
white-space: nowrap;
cursor: pointer;
}
.nav-item * {
text-decoration: none;
}
.nav-item:hover,
.popup li:hover,
.active {
border-bottom: 2px solid #756aee;
transform: translateY(-5%);
filter: drop-shadow(0px 0px 15px #fff);
}
.nav img {
height: 195%;
margin: 0;
cursor: pointer;
}
.nav img:hover {
filter: drop-shadow(-4px 8px 10px #756aee);
transition: all 0.1s;
}
.popup {
position: absolute;
list-style: none;
padding: 15px;
margin-top: 12px;
margin-left: -10px;
line-height: 38px;
border-radius: 5px;
box-shadow: 0px 0px 15px #0005;
background: #fff;
/* display: none; */
}
.nav-item:hover .popup {
display: inherit;
}
<script src="https://unpkg.com/vue#3.0.11/dist/vue.global.js"></script>
<div id="app">
<nav class="tr">
<div class="nav">
<span ref="spacer" class="spacer"></span>
<menu-item :name="key" :val="val" v-for="(val, key) in menu" :key="'menu' + key" />
</div>
</nav>
</div>
This works well. However, when I try to add transition component and enclose ul.popup in transition component, it does not behave properly and opacity becomes 0 even when mouse is on the popup menu. Below is the snippet showing this.
const menuItem = {
props: ['name', 'val'],
data() {
return {
showChild: false
}
},
template: /*html */ `
<div class="nav-item" #mouseover="showChild=true" #mouseout="showChild=false">
<span v-if="typeof val === 'string' || val instanceof String">
<a :href="val" target="_blank" rel="noopener noreferrer">{{name}}</a>
</span>
<div v-else>
{{name}}
<transition name="fade">
<ul class="popup" v-show="showChild">
<li v-for="(link, name) in val">
<a :href="link" target="_blank" rel="noopener noreferrer">{{name}}</a>
</li>
</ul>
</transition>
</div>
</div>
`
}
const app = Vue.createApp({
components: {
menuItem
},
data() {
return {
menu: {
'Home': '#',
'Services': {
'Software Development': 'https://www.upwork.com/signup/create-account/client_contact_freelancer?ciphertext=~0142999d8b15001517&BYOC',
'Business Training & Frenchise': 'https://www.badabusiness.com/dd/BIMK003866',
'Organic Marketing Training & Affiliate Program': 'https://leads-arc.web.app/'
},
'Our Apps': {
'All': 'https://play.google.com/store/apps/collection/cluster?clp=igM4ChkKEzUwMDkwNjA5NzAwNjg3NTk4ODIQCBgDEhkKEzUwMDkwNjA5NzAwNjg3NTk4ODIQCBgDGAA%3D:S:ANO1ljIhW_g&gsr=CjuKAzgKGQoTNTAwOTA2MDk3MDA2ODc1OTg4MhAIGAMSGQoTNTAwOTA2MDk3MDA2ODc1OTg4MhAIGAMYAA%3D%3D:S:ANO1ljJmSZ8',
'Featured': 'https://play.google.com/store/apps/dev?id=5009060970068759882',
'Srila Prabhupada Vani': 'https://play.google.com/store/apps/details?id=com.mayank.srilaprabhupadavani',
'ChatEasy - Easy Messaging': 'https://play.google.com/store/apps/details?id=c.kapps.easymessage.free'
},
'Blogs': 'https://mayank-1513.medium.com/',
'Contact Us': 'https://mayank-chaudhari.web.app/',
},
}
}
})
app.mount('#app');
* {
max-width: 1600px;
margin: auto;
transition: 0.2s all cubic-bezier(0.65, 0.05, 0.36, 1);
color: #2c3e50;
cursor: unset;
box-sizing: border-box;
}
body,
html,
#app {
margin: 0;
padding: 0;
font-family: Avenir, Helvetica, Arial, sans-serif;
max-width: 100%;
}
nav {
display: flex;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 50;
background: transparent;
align-items: center;
align-content: center;
justify-content: center;
}
nav.tr {
background: white;
box-shadow: #5555 0 0 0 2px;
height: 60px;
}
.nav {
display: flex;
align-items: center;
width: 100%;
padding: 15px;
height: 50px;
}
.nav-item {
display: inline-block;
position: relative;
padding: 10px 0;
margin: 20px;
font-weight: bold;
white-space: nowrap;
cursor: pointer;
}
.nav-item * {
text-decoration: none;
}
.nav-item:hover,
.popup li:hover,
.active {
border-bottom: 2px solid #756aee;
transform: translateY(-5%);
filter: drop-shadow(0px 0px 15px #fff);
}
.nav img {
height: 195%;
margin: 0;
cursor: pointer;
}
.nav img:hover {
filter: drop-shadow(-4px 8px 10px #756aee);
transition: all 0.1s;
}
.popup {
position: absolute;
list-style: none;
padding: 15px;
margin-top: 12px;
margin-left: -10px;
line-height: 38px;
border-radius: 5px;
box-shadow: 0px 0px 15px #0005;
background: #fff;
/* display: none; */
}
.nav-item:hover .popup {
display: inherit;
}
.fade-enter-active,
.fade-leave-active {
transition: all .5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
<script src="https://unpkg.com/vue#3.0.11/dist/vue.global.js"></script>
<div id="app">
<nav class="tr">
<div class="nav">
<span ref="spacer" class="spacer"></span>
<menu-item :name="key" :val="val" v-for="(val, key) in menu" :key="'menu' + key" />
</div>
</nav>
</div>
How do I fix this issue?
Try to use
#mouseenter and #mouseleave combination
There was issue with the event that I was listening to. Adding a detailed answer here for benefit of others looking for solution to similar question.
See the WC3 documentation here
The mouseover event triggers when the mouse pointer enters the div element, and its child elements.
The mouseenter event is only triggered when the mouse pointer enters the div element.
changing #mouseover to #mouseenter and #mouseout to #mouseleave solves the issue.

Delete button not working after adding another entry to my Library object

I have a problem that my delete button (the yellow one) works perfectly on preloaded book library items, but it isn't on the new entry when I add a book and want to delete it... I also want you to ask what it would be the easiest way to delete books also from myLibrary array... Thanks.
I've attached my code here. Any help will be appreciated. Thanks in advance.
//DOM
const bookForm = document.querySelector(".book-form");
// Calling a form when clicking on add book button
function openNav() {
document.getElementById("myNav").style.height = "100%";
console.log("dsafsa");
}
function closeNav() {
document.getElementById("myNav").style.height = "0%";
}
// where the books will be saved...
let myLibrary = [{
title: "Harry Potter - and the Philosopher's Stone",
author: "J. K. Rowling",
pages: 223,
readStatus: "no",
},
{
title: "The Hobbit",
author: "J.R.R. Tolkien",
pages: 304,
readStatus: "yes",
},
];
// book object
function Book(title, author, pages, readStatus) {
(this.title = title),
(this.author = author),
(this.pages = pages),
(this.readStatus = readStatus);
}
let i = "";
// render the book on page load...
function render() {
const books = myLibrary;
books.forEach((book) => {
addNewBookUI(book);
});
}
render();
document.querySelector(".book-form").addEventListener("submit", (e) => {
// prevent actual submit
e.preventDefault();
// get values
const title = document.querySelector("#title").value;
const author = document.querySelector("#author").value;
const pages = document.querySelector("#pages").value;
const readStatus = document.querySelector('input[name="yes_no"]:checked')
.value;
// prevent empty fields ...
if (title === "" || author === "" || pages === "0") {
alert("Missing data");
} else {
const book = new Book(title, author, pages, readStatus);
myLibrary.push(book);
addNewBookUI(book);
clearFormFields()
}
});
function addNewBookUI(book) {
if (book.readStatus === "yes") {
i = "checked";
} else {
i = "";
}
const main = document.querySelector(".main");
const bookCard = document.createElement("div");
bookCard.classList.add("book-card");
bookCard.innerHTML = `<div class="delete_button"><button class="delete btn"><i class="fa fa-trash">
</i></button></div><div class="title">${book.title}</div><div class="author">${book.author}
</div><div class="pages">${book.pages}</div><div class="read_status">Read: <input type="checkbox" id="yes" name="readstatus" value="yes" ${i}>
</div>`;
main.appendChild(bookCard);
}
// clear form fields after submit
function clearFormFields() {
const myForm = document.getElementById("myForm");
myForm.reset();
}
// Add event listener to all deleteButton
const deleteButton = document.querySelectorAll(".delete");
// deletes book UI;
deleteButton.forEach((el) => {
el.addEventListener("click", function () {
el.parentElement.parentElement.remove()
console.log("sas")
})
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
}
header {
color: #ffffff;
display: flex;
font-size: 1.4rem;
justify-content: space-between;
align-items: center;
background-color: #155999;
border-bottom: #172f4f solid 10px;
}
.logo {
margin-left: 10px;
}
header button {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-right: 10px;
cursor: pointer;
}
.plus-sign {
padding-right: 7px;
}
.main {
position: absolute;
width: 100%;
height: 100%;
background-color: #183153;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.book-card {
text-align: center;
font-weight: 1000;
display: flex;
flex-direction: column;
justify-content: space-evenly;
width: 250px;
height: 350px;
border-radius: 10px;
background-color: #155999;
margin-left: 20px;
margin-top: 10px;
color: #ffffff;
border: #172f4f solid 8px;
line-height: 30px;
position: relative;
padding-left: 7px;
padding-right: 7px;
box-shadow: 10px 4px 22px -5px rgba(21, 89, 153, 1);
}
.overlay {
height: 0%;
width: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(21, 89, 153);
background-color: rgba(21, 89, 153, 0.7);
overflow-y: hidden;
transition: 0.5s;
}
.overlay-content {
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
display: flex;
flex-direction: column;
font-size: 30px;
}
.overlay a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #ffffff;
display: block;
transition: 0.3s;
}
.overlay a:hover,
.overlay a:focus {
color: #c3c6d1;
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
}
#media screen and (max-height: 450px) {
.overlay {
overflow-y: auto;
}
.overlay a {
font-size: 20px
}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
.book-card div {
margin-top: 15px;
}
/* Style buttons */
.btn {
background-color: #ffd43b;
/* Blue background */
border: none;
/* Remove borders */
color: red;
/* White text */
padding: 12px 16px;
/* Some padding */
font-size: 16px;
/* Set a font size */
cursor: pointer;
/* Mouse pointer on hover */
border-radius: 50%;
position: absolute;
top: -20px;
right: -15px;
}
/* Darker background on mouse-over */
.btn:hover {
background-color: #183153;
}
.delete_button {
top: 0;
right: 0;
}
form div {
margin-top: 15px;
font-family: 'Roboto', sans-serif;
color: white;
font-weight: bold;
font-size: 30px;
margin-bottom: 10px;
}
.radiobutton {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.form-flex {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.form-flex input {
width: 50%;
border-radius: 5px;
height: 30px;
margin-top: 5px
}
.form-flex input::placeholder {
text-align: center;
}
input[type=submit] {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-top: -30px;
cursor: pointer;
}
.radiobutton p {
margin-top: 10px;
margin-bottom: 30px;
}
.flexbuttons {
display: flex;
margin-top: -50px;
margin-bottom: -25px;
}
input[type="text"] {
font-size: 24px;
text-align: center;
}
<!-- The overlay -->
<div id="myNav" class="overlay">
<!-- Button to close the overlay navigation -->
×
<!-- Overlay content -->
<div class="overlay-content">
<form id="myForm" class="book-form">
<div class="form-flex">
<label for="title">Book name:</label>
<input type="text" id="title" name="title" placeholder="Book name...">
</div>
<div class="form-flex">
<label for="author">Book author:</label>
<input type="text" id="author" name="author" placeholder="Book author...">
</div >
<div class="form-flex">
<label for="pages">Pages:</label>
<input type="number" id="pages" placeholder="0" name="pages">
</div>
<div class="radiobutton">
<p>Have you read a book?</p>
<div class="flexbuttons">
<div>
<p><input type="radio" id="huey" name="yes_no" value="yes" checked>
<label for="huey">yes</label>
</p>
</div>
<div>
<p><input type="radio" id="no" name="yes_no" value="no">
<label for="dewey">no</label>
</p>
</div>
</div>
</div>
<div><input type="submit" value="Add Book"></div>
</form>
</div>
</form>
</div>
</div>
</div>
<header>
<div class="logo">
<h1><i class="fa fa-book" aria-hidden="true"></i>
</i>Library
</h1>
</div>
<div class="button">
<button onclick="openNav()" class="add-book">
<i class="fa fa-plus plus-sign"></i>
Add book</button>
</div>
</header>
<div class="main">
</div>
<script src="./index.js" defer></script>
<script src="https://use.fontawesome.com/30a34909cc.js"></script>
You assigned the click event at loading time to all existing buttons with class=="delete". This will naturally not include the ones you might add dynamically at a later stage.
If you want all ".delete" buttons to have the click-event attached to them you need to do a "delegated event attachment" (edited, removes myLibrary element too now):
// Add event listener to all current and future deleteButtons
document.querySelector('.main').onclick=ev=>{
let el= ev.target.classList.contains('fa-trash')? ev.target.parentElement : ev.target.classList.contains('delete') ? ev.target : false;
if (el) {
let card=el.parentElement.parentElement; // book-card DOM element
// remove myLibrary array-element here:
myLibrary.splice( [...card.parentElement.children].indexOf(card) ,1);
console.log(myLibrary)
// remove card DOM element:
card.remove()
}
}
This will bind the click event handler to the .main div and will react only if the clicked element has a class=='fa-trash' or class=='delete'. In the first case it will "move up" one level (assign the parent element, i. e. the button to el), otherwise the clicked element is the button itself. If none of these classes are found, el becomes false and nothing happens. Otherwise the "Grandparent" of el is removed with `el.parentElement.parentElement.remove()' .
And please try and make your MCVE a little smaller next time, as it no fun to handle this amount of code in a small Stackoverflow snippet window! A true MCVE will get you more and faster responses!
Below is a working snippet, check it out:
//DOM
const bookForm = document.querySelector(".book-form");
// Calling a form when clicking on add book button
function openNav() {
document.getElementById("myNav").style.height = "100%";
console.log("dsafsa");
}
function closeNav() {
document.getElementById("myNav").style.height = "0%";
}
// where the books will be saved...
let myLibrary = [
{
title: "Harry Potter - and the Philosopher's Stone",
author: "J. K. Rowling",
pages: 223,
readStatus: "no",
},
{
title: "The Hobbit",
author: "J.R.R. Tolkien",
pages: 304,
readStatus: "yes",
},
];
// book object
function Book(title, author, pages, readStatus) {
(this.title = title),
(this.author = author),
(this.pages = pages),
(this.readStatus = readStatus);
}
let i = "";
// render the book on page load...
function render() {
const books = myLibrary;
books.forEach((book) => {
addNewBookUI(book);
});
}
render();
document.querySelector(".book-form").addEventListener("submit", (e) => {
// prevent actual submit
e.preventDefault();
// get values
const title = document.querySelector("#title").value;
const author = document.querySelector("#author").value;
const pages = document.querySelector("#pages").value;
const readStatus = document.querySelector('input[name="yes_no"]:checked')
.value;
// prevent empty fields ...
if (title === "" || author === "" || pages === "0") {
alert("Missing data");
} else {
const book = new Book(title, author, pages, readStatus);
myLibrary.push(book);
addNewBookUI(book);
clearFormFields()
}
});
function addNewBookUI(book) {
if (book.readStatus === "yes") {
i = "checked";
} else {
i = "";
}
const main = document.querySelector(".main");
const bookCard = document.createElement("div");
bookCard.classList.add("book-card");
bookCard.innerHTML = `<div class="delete_button"><button class="delete btn"><i class="fa fa-trash">
</i></button></div><div class="title">${book.title}</div><div class="author">${book.author}
</div><div class="pages">${book.pages}</div><div class="read_status">Read: <input type="checkbox" id="yes" name="readstatus" value="yes" ${i}>
</div>`;
main.appendChild(bookCard);
}
// clear form fields after submit
function clearFormFields() {
const myForm = document.getElementById("myForm");
myForm.reset();
}
// Add event listener to all deleteButton
document.querySelector('.main').onclick=ev=>{
let el= ev.target.classList.contains('fa-trash')? ev.target.parentElement : ev.target.classList.contains('delete') ? ev.target : false;
if (el) {
let card=el.parentElement.parentElement;
myLibrary.splice( [...card.parentElement.children].indexOf(card) ,1);
console.log(myLibrary)
card.remove()
}
}
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
}
header {
color: #ffffff;
display: flex;
font-size: 1.4rem;
justify-content: space-between;
align-items: center;
background-color:#155999;
border-bottom: #172f4f solid 10px;
}
.logo {
margin-left: 10px;
}
header button {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-right: 10px;
cursor: pointer;
}
.plus-sign {
padding-right: 7px;
}
.main {
position: absolute;
width: 100%;
height: 100%;
background-color: #183153;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.book-card {
text-align: center;
font-weight: 1000;
display: flex;
flex-direction: column;
justify-content: space-evenly;
width: 250px;
height: 350px;
border-radius: 10px;
background-color: #155999;
margin-left: 20px;
margin-top:10px;
color: #ffffff;
border: #172f4f solid 8px;
line-height: 30px;
position: relative;
padding-left: 7px;
padding-right: 7px;
box-shadow: 10px 4px 22px -5px rgba(21,89,153,1);
}
.overlay {
height: 0%;
width: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(21,89,153);
background-color: rgba(21,89,153,0.7);
overflow-y: hidden;
transition: 0.5s;
}
.overlay-content {
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
display: flex;
flex-direction: column;
font-size: 30px;
}
.overlay a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #ffffff;
display: block;
transition: 0.3s;
}
.overlay a:hover, .overlay a:focus {
color: #c3c6d1;
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
}
#media screen and (max-height: 450px) {
.overlay {overflow-y: auto;}
.overlay a {font-size: 20px}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
.book-card div {
margin-top:15px;
}
/* Style buttons */
.btn {
background-color: #ffd43b; /* Blue background */
border: none; /* Remove borders */
color: red; /* White text */
padding: 12px 16px; /* Some padding */
font-size: 16px; /* Set a font size */
cursor: pointer; /* Mouse pointer on hover */
border-radius: 50%;
position:absolute;
top:-20px;
right:-15px;
}
/* Darker background on mouse-over */
.btn:hover {
background-color: #183153;
}
.delete_button {
top:0;
right:0;
}
form div {
margin-top: 15px;
font-family: 'Roboto', sans-serif;
color:white;
font-weight: bold;
font-size: 30px;
margin-bottom: 10px;
}
.radiobutton {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.form-flex {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.form-flex input {
width: 50%;
border-radius: 5px;
height: 30px;
margin-top: 5px
}
.form-flex input::placeholder {
text-align: center;
}
input[type=submit] {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-top: -30px;
cursor: pointer;
}
.radiobutton p {
margin-top:10px;
margin-bottom: 30px;
}
.flexbuttons {
display: flex;
margin-top: -50px;
margin-bottom: -25px;
}
input[type="text"]
{
font-size:24px;
text-align: center;
}
JS:
//DOM
const bookForm = document.querySelector(".book-form");
<!-- The overlay -->
<div id="myNav" class="overlay">
<!-- Button to close the overlay navigation -->
×
<!-- Overlay content -->
<div class="overlay-content">
<form id="myForm" class="book-form">
<div class="form-flex">
<label for="title">Book name:</label>
<input type="text" id="title" name="title" placeholder="Book name...">
</div>
<div class="form-flex">
<label for="author">Book author:</label>
<input type="text" id="author" name="author" placeholder="Book author...">
</div >
<div class="form-flex">
<label for="pages">Pages:</label>
<input type="number" id="pages" placeholder="0" name="pages">
</div>
<div class="radiobutton">
<p>Have you read a book?</p>
<div class="flexbuttons">
<div><p><input type="radio" id="huey" name="yes_no" value="yes" checked>
<label for="huey">yes</label></p>
</div>
<div><p><input type="radio" id="no" name="yes_no" value="no">
<label for="dewey">no</label></p>
</div>
</div>
</div>
<div><input type="submit" value="Add Book"></div>
</form>
</div>
</form>
</div>
</div>
</div>
<header>
<div class="logo">
<h1><i class="fa fa-book" aria-hidden="true"></i>
</i>Library</h1>
</div>
<div class="button">
<button onclick="openNav()" class="add-book">
<i class="fa fa-plus plus-sign"></i>
Add book</button>
</div>
</header>
<div class="main">
</div>
<script src="./index.js" defer></script>
<script src="https://use.fontawesome.com/30a34909cc.js"></script>

Categories

Resources