uzilö
This commit is contained in:
parent
b9fd729f2c
commit
68e7a93f91
@ -1,22 +1,21 @@
|
|||||||
const CARDS_PER_PAGE = 18;
|
const CARDS_PER_PAGE = 18;
|
||||||
|
|
||||||
let currentGroupId = null;
|
let currentGroupId = null;
|
||||||
let currentPage = 1;
|
let currentPage = 1;
|
||||||
let currentDeckId = null;
|
let currentDeckId = null;
|
||||||
let deckCards = []; // [{card_id, amount}]
|
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,16 +515,18 @@ 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
|
||||||
const color = g.color || "#6b4b2a";
|
.map((g, i) => {
|
||||||
return `
|
const color = g.color || "#6b4b2a";
|
||||||
|
return `
|
||||||
<button class="kd-tab ${i === 0 ? "kd-tab-active" : ""}"
|
<button class="kd-tab ${i === 0 ? "kd-tab-active" : ""}"
|
||||||
data-group="${g.id}"
|
data-group="${g.id}"
|
||||||
style="border-color:${color};${i === 0 ? `background:${color}33;` : ""}">
|
style="border-color:${color};${i === 0 ? `background:${color}33;` : ""}">
|
||||||
<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 () => {
|
||||||
@ -550,7 +551,7 @@ function renderTabs(groups) {
|
|||||||
totalPages, total }
|
totalPages, total }
|
||||||
══════════════════════════════════════════════ */
|
══════════════════════════════════════════════ */
|
||||||
async function loadUserCards() {
|
async function loadUserCards() {
|
||||||
const grid = document.getElementById("kd-grid");
|
const grid = document.getElementById("kd-grid");
|
||||||
const pagination = document.getElementById("kd-pagination");
|
const pagination = document.getElementById("kd-pagination");
|
||||||
if (!grid) return;
|
if (!grid) return;
|
||||||
|
|
||||||
@ -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,17 +749,18 @@ 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
|
||||||
const inDeck = getDeckCount(c.card_id);
|
.map((c) => {
|
||||||
const maxed = isMaxedOut(c, inDeck, totalInDeck);
|
const inDeck = getDeckCount(c.card_id);
|
||||||
return `
|
const maxed = isMaxedOut(c, inDeck, totalInDeck);
|
||||||
|
return `
|
||||||
<div class="kd-card ${maxed ? "kd-card-maxed" : ""}"
|
<div class="kd-card ${maxed ? "kd-card-maxed" : ""}"
|
||||||
data-card-id="${c.card_id}"
|
data-card-id="${c.card_id}"
|
||||||
title="${c.name}">
|
title="${c.name}">
|
||||||
<img src="/images/cards/${c.image}" alt="${c.name}"
|
<img src="/images/cards/${c.image}" alt="${c.name}"
|
||||||
onerror="this.src='/images/avatar_placeholder.svg'">
|
onerror="this.src='/images/avatar_placeholder.svg'">
|
||||||
${c.attack != null ? `<span class="kd-stat-atk">${c.attack}</span>` : ""}
|
${c.attack != null ? `<span class="kd-stat-atk">${c.attack}</span>` : ""}
|
||||||
${c.defends != null ? `<span class="kd-stat-def">${c.defends}</span>` : ""}
|
${c.defends != null ? `<span class="kd-stat-def">${c.defends}</span>` : ""}
|
||||||
${c.cooldown != null ? `<span class="kd-stat-cd">${c.cooldown}</span>` : ""}
|
${c.cooldown != null ? `<span class="kd-stat-cd">${c.cooldown}</span>` : ""}
|
||||||
<div class="kd-card-footer">
|
<div class="kd-card-footer">
|
||||||
<span class="kd-count-owned" title="Besitzt du">${c.amount}×</span>
|
<span class="kd-count-owned" title="Besitzt du">${c.amount}×</span>
|
||||||
@ -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,10 +788,11 @@ 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 ownedAmt = ownedEntry ? ownedEntry.amount : "?";
|
const ownedEntry = userCardsCache.find((u) => u.card_id === c.card_id);
|
||||||
return `
|
const ownedAmt = ownedEntry ? ownedEntry.amount : "?";
|
||||||
|
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}">
|
||||||
<img src="/images/cards/${c.image}" alt="${c.name}"
|
<img src="/images/cards/${c.image}" alt="${c.name}"
|
||||||
onerror="this.src='/images/avatar_placeholder.svg'">
|
onerror="this.src='/images/avatar_placeholder.svg'">
|
||||||
@ -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,14 +927,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMaxedOut(card, inDeck, totalInDeck) {
|
function isMaxedOut(card, inDeck, totalInDeck) {
|
||||||
if (!currentDeckId) return false;
|
if (!currentDeckId) return false;
|
||||||
if (totalInDeck >= 30) return true;
|
if (totalInDeck >= 30) return true;
|
||||||
if (inDeck >= card.amount) return true; // mehr als besessen
|
if (inDeck >= card.amount) return true; // mehr als besessen
|
||||||
if (parseInt(card.rarity) > 5 && inDeck >= 1) return true; // Rarity > 5: nur 1x
|
if (parseInt(card.rarity) > 5 && inDeck >= 1) return true; // Rarity > 5: nur 1x
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user