I am trying to make a deck builder where the user can click on a card and it adds the matching Card-frame to a deck list on the side in another container. Is this approach I have below the right direction and a good start, or should I look at a different solution? Right now When I click add, it only will add one of the card frames. Eventually I want to keep track of what cards are in the list and the quantity. I also want to incorporate GSAP to animate the Card-Frame moving to the list container.
function addItem() {
const node = document.querySelector(".card-body");
const clone = node.cloneNode(true);
document.getElementById("box").appendChild(clone);
}
.container {
display: grid;
grid-template-columns: 250px 250px 300px;
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.card-image {
background-color: rgb(223, 223, 223);
padding: 10px;
border: 2px solid #b60606;
}
.card-frame {
background-color: rgb(204, 204, 204);
padding: 20px;
border: 2px solid #000000;
object-fit: cover;
}
.card-image img {
background-color: #b60606;
padding: 10px;
border: 2px solid #ddd;
height: 300px;
}
.card-frame img {
height: 50px;
padding: 0px 0px 20px 0px;
}
.card-body img {
height: 50px;
padding: 0px 0px 10px 0px;
}
<div class="container">
<div class="card-image">
<img src="" alt="">
<button onclick="addItem()">ADD!</button>
</div>
<div class="card-image">
<img src="" alt="">
<button onclick="addItem()">ADD!</button>
</div>
<div class="card-frame">
<div class="card" id="box">
<div class="card-body">
<h5 class="card-title" id="Cat1"></h5>
<img src="" alt="">
</div>
</div>
<div class="card" id="box">
<div class="card-body">
<h5 class="card-title" id="Cat1"></h5>
<img src="" alt="">
</div>
</div>
</div>
</div>
I am trying to make a deck builder where the user can click on a card and it adds the matching Card-frame to a deck list on the side in another container. Is this approach I have below the right direction and a good start, or should I look at a different solution? Right now When I click add, it only will add one of the card frames. Eventually I want to keep track of what cards are in the list and the quantity. I also want to incorporate GSAP to animate the Card-Frame moving to the list container.
function addItem() {
const node = document.querySelector(".card-body");
const clone = node.cloneNode(true);
document.getElementById("box").appendChild(clone);
}
.container {
display: grid;
grid-template-columns: 250px 250px 300px;
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.card-image {
background-color: rgb(223, 223, 223);
padding: 10px;
border: 2px solid #b60606;
}
.card-frame {
background-color: rgb(204, 204, 204);
padding: 20px;
border: 2px solid #000000;
object-fit: cover;
}
.card-image img {
background-color: #b60606;
padding: 10px;
border: 2px solid #ddd;
height: 300px;
}
.card-frame img {
height: 50px;
padding: 0px 0px 20px 0px;
}
.card-body img {
height: 50px;
padding: 0px 0px 10px 0px;
}
<div class="container">
<div class="card-image">
<img src="https://placehold.co/200x300/blue/white?text=Aeito" alt="">
<button onclick="addItem()">ADD!</button>
</div>
<div class="card-image">
<img src="https://placehold.co/200x300/orange/white?text=Scipius" alt="">
<button onclick="addItem()">ADD!</button>
</div>
<div class="card-frame">
<div class="card" id="box">
<div class="card-body">
<h5 class="card-title" id="Cat1"></h5>
<img src="https://placehold.co/200x300/blue/white?text=Aeito" alt="">
</div>
</div>
<div class="card" id="box">
<div class="card-body">
<h5 class="card-title" id="Cat1"></h5>
<img src="https://placehold.co/200x300/orange/white?text=Scipius" alt="">
</div>
</div>
</div>
</div>
Share
Improve this question
edited Mar 14 at 1:17
Yogi
7,3443 gold badges32 silver badges40 bronze badges
asked Mar 13 at 21:58
artcankartcank
1
0
1 Answer
Reset to default 0When creating an app with user interactivity and hooks you usually have a few parts.
- Display
- State
- Hooks
All these parts should operate fairly independently. The idea is by making things as modular as possible, you can update, extend, and add features to any part in the future, and it also makes the code more readable and reusable.
It's also worth mentioning that usually a framework is used to manage larger projects, but let me give you a small demo using vanilla web.
In my html, I only provide a target for content to be rendered. This way I'm not cloning existing html elements or relying too heavily on a specific structure. I can move my deck or add-controls to any area I want.
I use js to create functions for actions, in case there is a change in how a "CardEl" is built, I only have to update it in one place.
I have my "state" or the information regarding what cards the deck has, all contained in js, and I do not rely on my display to store any data. The responsibility of the display is to render a graphical representation of how my state is stored inside js.
I have a hook or event listener added to the add-cards button, which can update state inside js, and trigger a re-render of the display.
Hopefully this demo starts pointing you in the right direction! If you have any questions, I'm happy to help.
const createCardEl = cardName => {
const cardFrame = document.createElement("div");
cardFrame.classList.add("card-frame");
const cardTitle = document.createElement("p");
cardTitle.innerText = cardName;
cardFrame.appendChild(cardTitle);
return cardFrame;
};
const DEFAULT_CARD_TYPES = [
"Ace",
"Bird",
"Fire",
"John"
];
const deck = Object.fromEntries(
DEFAULT_CARD_TYPES.map(
cardType => [cardType, 0]
)
);
const deckEl = document.querySelector(".deck");
const renderCards = () => {
deckEl.innerHTML = "";
const deckEntries = Object.entries(deck);
for (const [cardType, numOfCard] of deckEntries) {
for (let i = 0; i < numOfCard; i++) {
const card = createCardEl(cardType);
deckEl.appendChild(card);
}
}
};
const addCardToDeck = cardType => {
deck[cardType] += 1;
renderCards();
};
const addCardArea = document.querySelector(".add-cards");
DEFAULT_CARD_TYPES.forEach(cardType => {
const card = createCardEl(cardType);
const addButton = document.createElement("button");
addButton.innerText = "+";
card.appendChild(addButton);
addCardArea.appendChild(card);
addButton.addEventListener("click", () => {
addCardToDeck(cardType);
});
});
.card-frame {
aspect-ratio: 2 / 3;
width: 100px;
background: lightgrey;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
transition: background 0.2s;
&:has(button:hover) {
background: lightblue;
}
}
.add-cards, .deck {
display: flex;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
}
<div class="add-cards"></div>
<hr>
<div class="deck"></div>