This commit is contained in:
cay 2026-04-04 11:12:41 +01:00
parent b9fd729f2c
commit 68e7a93f91

View File

@ -7,16 +7,15 @@ let deckCards = []; // [{card_id, amount}]
let userCardsCache = []; // aktuelle Seite: [{card_id, amount, name, image, rarity, attack, defense}] let userCardsCache = []; // aktuelle Seite: [{card_id, amount, name, image, rarity, attack, defense}]
let decks = []; // [{id, name}] let decks = []; // [{id, name}]
/* ── Kristall-Mapping ───────────────────────── */ /* ── Kristall-Mapping ───────────────────────── */
const RARITY_CRYSTALS = { const RARITY_CRYSTALS = {
"1": "roter-cristal.png", 1: "roter-cristal.png",
"2": "blauer-cristal.png", 2: "blauer-cristal.png",
"3": "gelber-cristal.png", 3: "gelber-cristal.png",
"4": "gruener-cristal.png", 4: "gruener-cristal.png",
"5": "oranger-cristal.png", 5: "oranger-cristal.png",
"6": "violet-cristal.png", 6: "violet-cristal.png",
"7": "pinker-cristal.png", 7: "pinker-cristal.png",
}; };
function rarityImgs(rarity, size = 14) { function rarityImgs(rarity, size = 14) {
@ -250,8 +249,8 @@ function renderShell() {
} }
.kd-stat-atk { .kd-stat-atk {
position: absolute; position: absolute;
right: 4px; right: 12px;
top: 50%; top: 36%;
transform: translateY(-50%); transform: translateY(-50%);
background: rgba(180,40,20,0.88); background: rgba(180,40,20,0.88);
border: 1px solid #ff6040; border: 1px solid #ff6040;
@ -261,8 +260,8 @@ function renderShell() {
} }
.kd-stat-def { .kd-stat-def {
position: absolute; position: absolute;
left: 4px; left: 12px;
top: 50%; top: 36%;
transform: translateY(-50%); transform: translateY(-50%);
background: rgba(20,80,180,0.88); background: rgba(20,80,180,0.88);
border: 1px solid #4090ff; border: 1px solid #4090ff;
@ -272,8 +271,8 @@ function renderShell() {
} }
.kd-stat-cd { .kd-stat-cd {
position: absolute; position: absolute;
bottom: 3px; bottom: 16px;
right: 3px; right: 11px;
width: 22px; height: 22px; width: 22px; height: 22px;
border-radius: 50%; border-radius: 50%;
background: rgba(0,0,0,0.75); background: rgba(0,0,0,0.75);
@ -516,7 +515,8 @@ function renderTabs(groups) {
const container = document.getElementById("kd-tabs"); const container = document.getElementById("kd-tabs");
if (!container) return; if (!container) return;
container.innerHTML = groups.map((g, i) => { container.innerHTML = groups
.map((g, i) => {
const color = g.color || "#6b4b2a"; const color = g.color || "#6b4b2a";
return ` return `
<button class="kd-tab ${i === 0 ? "kd-tab-active" : ""}" <button class="kd-tab ${i === 0 ? "kd-tab-active" : ""}"
@ -525,7 +525,8 @@ function renderTabs(groups) {
<span class="kd-tab-dot" style="background:${color};"></span> <span class="kd-tab-dot" style="background:${color};"></span>
<span>${g.name}</span> <span>${g.name}</span>
</button>`; </button>`;
}).join(""); })
.join("");
container.querySelectorAll(".kd-tab").forEach((btn) => { container.querySelectorAll(".kd-tab").forEach((btn) => {
btn.addEventListener("click", async () => { btn.addEventListener("click", async () => {
@ -558,7 +559,9 @@ async function loadUserCards() {
pagination.innerHTML = ""; pagination.innerHTML = "";
try { try {
const res = await fetch(`/api/user-cards?group_id=${currentGroupId}&page=${currentPage}&limit=${CARDS_PER_PAGE}`); const res = await fetch(
`/api/user-cards?group_id=${currentGroupId}&page=${currentPage}&limit=${CARDS_PER_PAGE}`,
);
if (!res.ok) throw new Error("API Fehler"); if (!res.ok) throw new Error("API Fehler");
const data = await res.json(); const data = await res.json();
userCardsCache = data.cards || []; userCardsCache = data.cards || [];
@ -588,8 +591,14 @@ async function loadDecks() {
function renderDeckSelect() { function renderDeckSelect() {
const sel = document.getElementById("kd-deck-select"); const sel = document.getElementById("kd-deck-select");
if (!sel) return; if (!sel) return;
sel.innerHTML = `<option value="">— Deck wählen —</option>` + sel.innerHTML =
decks.map(d => `<option value="${d.id}" ${d.id === currentDeckId ? "selected" : ""}>${d.name}</option>`).join(""); `<option value="">— Deck wählen —</option>` +
decks
.map(
(d) =>
`<option value="${d.id}" ${d.id === currentDeckId ? "selected" : ""}>${d.name}</option>`,
)
.join("");
} }
/* /*
@ -643,7 +652,7 @@ async function addCardToDeck(card) {
// Rarity > 5: max. 1 Exemplar im Deck // Rarity > 5: max. 1 Exemplar im Deck
if (parseInt(card.rarity) > 5) { if (parseInt(card.rarity) > 5) {
const already = deckCards.find(c => c.card_id === card.card_id); const already = deckCards.find((c) => c.card_id === card.card_id);
if (already) { if (already) {
showToast("Karten ab Rarity 6 dürfen nur 1x im Deck sein."); showToast("Karten ab Rarity 6 dürfen nur 1x im Deck sein.");
return; return;
@ -740,7 +749,8 @@ function renderCollectionGrid(grid, cards) {
const totalInDeck = deckCards.reduce((s, c) => s + c.amount, 0); const totalInDeck = deckCards.reduce((s, c) => s + c.amount, 0);
grid.innerHTML = cards.map(c => { grid.innerHTML = cards
.map((c) => {
const inDeck = getDeckCount(c.card_id); const inDeck = getDeckCount(c.card_id);
const maxed = isMaxedOut(c, inDeck, totalInDeck); const maxed = isMaxedOut(c, inDeck, totalInDeck);
return ` return `
@ -758,11 +768,12 @@ function renderCollectionGrid(grid, cards) {
</div> </div>
${c.rarity ? `<div class="kd-rarity">${rarityImgs(c.rarity, 13)}</div>` : ""} ${c.rarity ? `<div class="kd-rarity">${rarityImgs(c.rarity, 13)}</div>` : ""}
</div>`; </div>`;
}).join(""); })
.join("");
grid.querySelectorAll(".kd-card:not(.kd-card-maxed)").forEach(el => { grid.querySelectorAll(".kd-card:not(.kd-card-maxed)").forEach((el) => {
el.addEventListener("click", async () => { el.addEventListener("click", async () => {
const card = cards.find(c => c.card_id === parseInt(el.dataset.cardId)); const card = cards.find((c) => c.card_id === parseInt(el.dataset.cardId));
if (card) await addCardToDeck(card); if (card) await addCardToDeck(card);
}); });
}); });
@ -777,8 +788,9 @@ function renderDeckGrid(grid, cards) {
return; return;
} }
// Owned-Anzahl aus userCardsCache auslesen // Owned-Anzahl aus userCardsCache auslesen
grid.innerHTML = cards.map(c => { grid.innerHTML = cards
const ownedEntry = userCardsCache.find(u => u.card_id === c.card_id); .map((c) => {
const ownedEntry = userCardsCache.find((u) => u.card_id === c.card_id);
const ownedAmt = ownedEntry ? ownedEntry.amount : "?"; const ownedAmt = ownedEntry ? ownedEntry.amount : "?";
return ` return `
<div class="kd-deck-card" data-card-id="${c.card_id}" title="Klicken zum Entfernen: ${c.name}"> <div class="kd-deck-card" data-card-id="${c.card_id}" title="Klicken zum Entfernen: ${c.name}">
@ -789,11 +801,12 @@ function renderDeckGrid(grid, cards) {
</div> </div>
${c.rarity ? `<div class="kd-rarity" style="top:75%">${rarityImgs(c.rarity, 14)}</div>` : ""} ${c.rarity ? `<div class="kd-rarity" style="top:75%">${rarityImgs(c.rarity, 14)}</div>` : ""}
</div>`; </div>`;
}).join(""); })
.join("");
grid.querySelectorAll(".kd-deck-card").forEach(el => { grid.querySelectorAll(".kd-deck-card").forEach((el) => {
el.addEventListener("click", async () => { el.addEventListener("click", async () => {
const card = cards.find(c => c.card_id === parseInt(el.dataset.cardId)); const card = cards.find((c) => c.card_id === parseInt(el.dataset.cardId));
if (card) await removeCardFromDeck(card); if (card) await removeCardFromDeck(card);
}); });
}); });
@ -806,19 +819,29 @@ function renderPagination(pagination, totalPages, total) {
if (!totalPages || totalPages <= 1) return; if (!totalPages || totalPages <= 1) return;
pagination.innerHTML = ` pagination.innerHTML = `
<button class="kd-page-btn" id="kd-prev" ${currentPage === 1 ? "disabled" : ""}></button> <button class="kd-page-btn" id="kd-prev" ${currentPage === 1 ? "disabled" : ""}></button>
${Array.from({ length: totalPages }, (_, i) => i + 1).map(p => ` ${Array.from({ length: totalPages }, (_, i) => i + 1)
.map(
(p) => `
<button class="kd-page-btn ${p === currentPage ? "kd-page-active" : ""}" data-page="${p}">${p}</button> <button class="kd-page-btn ${p === currentPage ? "kd-page-active" : ""}" data-page="${p}">${p}</button>
`).join("")} `,
)
.join("")}
<button class="kd-page-btn" id="kd-next" ${currentPage === totalPages ? "disabled" : ""}></button> <button class="kd-page-btn" id="kd-next" ${currentPage === totalPages ? "disabled" : ""}></button>
<span class="kd-page-info">${total} Karten</span>`; <span class="kd-page-info">${total} Karten</span>`;
pagination.querySelector("#kd-prev")?.addEventListener("click", async () => { pagination.querySelector("#kd-prev")?.addEventListener("click", async () => {
if (currentPage > 1) { currentPage--; await loadUserCards(); } if (currentPage > 1) {
currentPage--;
await loadUserCards();
}
}); });
pagination.querySelector("#kd-next")?.addEventListener("click", async () => { pagination.querySelector("#kd-next")?.addEventListener("click", async () => {
if (currentPage < totalPages) { currentPage++; await loadUserCards(); } if (currentPage < totalPages) {
currentPage++;
await loadUserCards();
}
}); });
pagination.querySelectorAll("[data-page]").forEach(btn => { pagination.querySelectorAll("[data-page]").forEach((btn) => {
btn.addEventListener("click", async () => { btn.addEventListener("click", async () => {
currentPage = parseInt(btn.dataset.page); currentPage = parseInt(btn.dataset.page);
await loadUserCards(); await loadUserCards();
@ -882,7 +905,10 @@ function showNewDeckModal() {
modal.querySelector("#kd-modal-cancel").onclick = () => modal.remove(); modal.querySelector("#kd-modal-cancel").onclick = () => modal.remove();
modal.querySelector("#kd-modal-confirm").onclick = async () => { modal.querySelector("#kd-modal-confirm").onclick = async () => {
const name = input.value.trim(); const name = input.value.trim();
if (!name) { input.focus(); return; } if (!name) {
input.focus();
return;
}
modal.remove(); modal.remove();
await createDeck(name); await createDeck(name);
}; };
@ -901,7 +927,7 @@ function showNewDeckModal() {
HELPERS HELPERS
*/ */
function getDeckCount(cardId) { function getDeckCount(cardId) {
const entry = deckCards.find(c => c.card_id === cardId); const entry = deckCards.find((c) => c.card_id === cardId);
return entry ? entry.amount : 0; return entry ? entry.amount : 0;
} }