[260111] 프로젝트 이전 및 초기화

This commit is contained in:
2026-01-11 21:02:18 +09:00
commit 4564805a2b
8874 changed files with 95182 additions and 0 deletions

30
.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Node.js
node_modules/
package-lock.json
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Build output
build/
dist/
# Logs
logs/
*.log
# Editor/IDE
.idea/
.vscode/
*.swp
.DS_Store
# 기타
/coverage

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"tabWidth": 2,
"useTabs": false
}

14
.prettierrc.json Normal file
View File

@@ -0,0 +1,14 @@
{
"arrowParens": "avoid",
"bracketSameLine": true,
"bracketSpacing": true,
"endOfLine": "auto",
"htmlWhitespaceSensitivity": "ignore",
"printWidth": 100,
"semi": true,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "all",
"useTabs": false,
"vueIndentScriptAndStyle": false
}

991
cardList.html Normal file
View File

@@ -0,0 +1,991 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<title>Card List</title>
<script src="/script/navigation.js"></script>
<script type="module" src="/i18n/i18n.js"></script>
<link href="/style/navigation.css" rel="stylesheet" />
<link href="/style/style.css" rel="stylesheet" />
<link href="/style/output.css" rel="stylesheet" />
</head>
<body>
<style>
.homeview_container {
display: flex;
flex-direction: column;
}
.ads_coupang iframe {
max-height: 96px;
}
@media screen and (min-width: 640px) {
.ads_coupang {
max-width: 100%;
overflow: hidden;
}
.homeview_container {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.ads_coupang iframe {
max-height: 128px;
}
}
#cardList {
padding-bottom: 128px;
}
</style>
<div id="app">
<!-- 로딩 -->
<div
id="loading-screen"
class="fixed top-0 left-0 w-full h-full bg-white flex justify-center items-center"
>
<div
class="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900"
></div>
</div>
<div class="homeview_container max-w-6xl lg:max-w-7xl mx-auto">
<div class="sm:col-span-1">
<div
class="aside-widget w-full mx-auto max-w-2xl sm:max-w-4xl lg:max-w-5xl xl:max-w-7xl flex gap-1 justify-between px-4 xl:px-2 sm:mt-20"
>
<div class="w-full flex flex-col gap-2 transition-all">
<div class="">
<div class="relative">
<label
for="name"
class="absolute -top-2 left-2 inline-block bg-white px-1 text-xs font-medium text-gray-900"
>Card Search</label
>
<input
type="text"
id="searchQuery"
class="block w-full rounded-md border-0 px-3 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
placeholder="ex) UA04BT/IMS-1-082"
/>
</div>
</div>
<div class="flex flex-col">
<h4 class="mt-4 font-bold text-lg">COLOR</h4>
<div class="flex flex-wrap gap-2 mt-4">
<button
type="button"
class="color-filter-btn px-3 py-1 rounded border"
data-color="All"
>
All
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Red"
>
Red
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Blue"
>
Blue
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Green"
>
Green
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Yellow"
>
Yellow
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Purple"
>
Purple
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="AP"
>
AP
</button>
<button
type="button"
class="color-filter-btn px-3 py-1 rounded"
data-color="Multi"
>
Multi
</button>
</div>
</div>
<div class="flex flex-col aside-accordion-widget">
<h4 class="mt-4 font-bold text-lg">TYPE</h4>
<div
class="checkbox-wrapper w-full flex flex-col gap-2 items-start py-2"
>
<div>
<input id="includeBasic" type="checkbox" checked />
<label for="includeBasic" data-i18n="includeBasic"></label>
</div>
<div>
<input id="includeAP" type="checkbox" />
<label
for="includeAP"
data-i18n="includeActionPoint"
></label>
</div>
<div>
<input id="includeParallel" type="checkbox" />
<label
for="includeParallel"
data-i18n="includeParallel"
></label>
</div>
</div>
<h4 class="mt-4 font-bold text-lg">TRIGGER</h4>
<div class="radio-wrapper w-full flex flex-col gap-2 py-2">
<div>
<input
id="includeAllTrigger"
type="radio"
name="triggerType"
value="allTrigger"
checked
/>
<label
for="includeAllTrigger"
class="ml-2"
data-i18n="includeAllTrigger"
>Include All Trigger</label
>
</div>
<div>
<input
id="includeColorTrigger"
type="radio"
name="triggerType"
value="colorTrigger"
/>
<label
for="includeColorTrigger"
class="ml-2"
data-i18n="includeColorTrigger"
>Include Color Trigger</label
>
</div>
<div>
<input
id="includeSpecialTrigger"
type="radio"
name="triggerType"
value="specialTrigger"
/>
<label
for="includeSpecialTrigger"
class="ml-2"
data-i18n="includeSpecialTrigger"
>Include Special Trigger</label
>
</div>
<div>
<input
id="includeFinalTrigger"
type="radio"
name="triggerType"
value="finalTrigger"
/>
<label
for="includeFinalTrigger"
class="ml-2"
data-i18n="includeFinalTrigger"
>Include Final Trigger</label
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="SelectedSeriesCardList col-span-3 mt-4 sm:mt-0">
<div
id="totalCount"
class="result_total_count text-center text-xl mb-8"
>
<span data-i18n="SearchResults"></span>:
<span id="SearchResultsCounter">0</span>
<span data-i18n="SearchResultsCounter"></span>
</div>
<div id="cardList">
<div
class="mx-auto max-w-2xl mb-24 px-4 sm:px-6 sm:max-w-4xl lg:max-w-5xl lg:px-8 xl:max-w-7xl"
>
<div
class="mt-6 grid grid-cols-3 gap-x-6 gap-y-6 lg:grid-cols-4 lg:gap-x-5 xl:grid-cols-5 xl:gap-x-8"
id="card-grid"
></div>
</div>
</div>
</div>
</div>
<div class="w-full fixed bottom-0 z-50">
<!-- 프리뷰 버튼 -->
<div class="w-full go-result-page-btn rounded-t-xl">
<!-- Coupang -->
<div class="ads_coupang">
<iframe
src="https://ads-partners.coupang.com/widgets.html?id=915533&template=carousel&trackingCode=AF6561083&subId=&width=1280&height=128&tsource="
width="100%"
height="128"
frameborder="0"
scrolling="no"
referrerpolicy="unsafe-url"
browsingtopics
></iframe>
</div>
<div
id="goToResultPage"
class="w-full h-12 cursor-pointer flex justify-center items-center bg-indigo-500 px-3 py-2 font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
data-i18n="makeDeckList"
></div>
</div>
<!-- 푸터 카드 현황 -->
<div
class="bottom-line w-full bg-black text-white text-center text-sm flex gap-4 justify-around items-center z-50"
>
<div class="copyright hidden sm:block">
KEY CARD: <span id="keyCardCount">0</span>/4
</div>
<div class="flex gap-4 select-none">
<div id="colorCount">
COLOR: <span id="colorCardCount">0</span>/4
</div>
<span>|</span>
<div id="finalCount">
FINAL: <span id="finalCardCount">0</span>/4
</div>
<span>|</span>
<div id="specialCount">
SPECIAL: <span id="specialCardCount">0</span>/4
</div>
<span>|</span>
<div id="totalCardsCount">
TOTAL: <span id="totalCardCount">0</span>
</div>
</div>
</div>
</div>
</div>
<div id="imageOverlay" class="overlay">
<img src="" alt="Card Preview" />
</div>
<script src="/script/loading.js"></script>
<script>
// 1. 변수 선언 및 초기화
let cardList;
let selectedCards = [];
let selectedColors = new Set(["All"]);
const colorButtons = document.querySelectorAll(".color-filter-btn");
const searchQueryInput = document.getElementById("searchQuery");
const includeBasicCheckbox = document.getElementById("includeBasic");
const includeAPCheckbox = document.getElementById("includeAP");
const includeParallelCheckbox =
document.getElementById("includeParallel");
const includeAllTriggerRadio =
document.getElementById("includeAllTrigger");
const includeSpecialTriggerRadio = document.getElementById(
"includeSpecialTrigger"
);
const includeColorTriggerRadio = document.getElementById(
"includeColorTrigger"
);
const includeFinalTriggerRadio = document.getElementById(
"includeFinalTrigger"
);
const keyCardCountElement = document.getElementById("keyCardCount");
const colorCardCountElement = document.getElementById("colorCardCount");
const finalCardCountElement = document.getElementById("finalCardCount");
const specialCardCountElement =
document.getElementById("specialCardCount");
const totalCardCountElement = document.getElementById("totalCardCount");
// 2. URL 파라미터 및 로컬 스토리지 관리
function getQueryParam(param) {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
}
const seriesKey = getQueryParam("series");
const nameKey = getQueryParam("seriesName");
if (seriesKey) {
localStorage.setItem(
"selectedSeries",
JSON.stringify({ key: seriesKey, name: nameKey })
);
}
// 3. 데이터 로딩 및 초기화
async function loadCardData() {
try {
const module = await import(`./datas/${seriesKey}.js`);
cardList = module.cardList;
const urlParams = new URLSearchParams(window.location.search);
const cardsParam = urlParams.get("cards");
if (cardsParam) {
const parsedCards = JSON.parse(decodeURIComponent(cardsParam));
cardList = updateCardListFromStorage(cardList, parsedCards);
selectedCards = parsedCards;
displayCardList(cardList);
updateCardList();
} else {
const savedSelectedCards = localStorage.getItem("selectedCards");
if (savedSelectedCards) {
const parsedCards = JSON.parse(
decodeURIComponent(savedSelectedCards)
);
cardList = updateCardListFromStorage(cardList, parsedCards);
selectedCards = parsedCards;
displayCardList(cardList);
updateCardList();
} else {
applyInitialFilter();
}
}
const loadingScreen = document.getElementById("loading-screen");
if (loadingScreen) {
loadingScreen.style.display = "none";
}
updateCounters();
} catch (error) {
console.error("Failed to load card data:", error);
}
}
document.addEventListener("DOMContentLoaded", async () => {
const loadingScreen = document.getElementById("loading-screen");
if (loadingScreen) {
loadingScreen.style.display = "flex";
}
await loadCardData();
const goToResultPage = document.getElementById("goToResultPage");
if (goToResultPage) {
goToResultPage.addEventListener("click", () => {
const queryParams = encodeURIComponent(
JSON.stringify(selectedCards)
);
const seriesKey = getQueryParam("series");
const nameKey = getQueryParam("seriesName");
localStorage.setItem("selectedCards", queryParams);
localStorage.setItem(
"selectedSeries",
JSON.stringify({ key: seriesKey, name: nameKey })
);
window.location.href = `/result.html?series=${seriesKey}&seriesName=${nameKey}&cards=${queryParams}`;
});
}
});
function applyInitialFilter() {
const filteredList = cardList.filter(
(card) => card.color !== "AP" && !card.parallel
);
document.getElementById("includeBasic").checked = true;
document.getElementById("includeAP").checked = false;
document.getElementById("includeParallel").checked = false;
displayCardList(filteredList);
}
function updateCardListFromStorage(cardList, savedSelectedCards) {
const cardMap = new Map(cardList.map((card) => [card.imgSrc, card]));
savedSelectedCards.forEach((savedCard) => {
const uniqueKey = savedCard.imgSrc;
const existingCard = cardMap.get(uniqueKey);
if (existingCard) {
existingCard.count = savedCard.count;
existingCard.key = savedCard.key;
}
});
return Array.from(cardMap.values());
}
const RARITY_STYLE_RULES = [
{
// 🌈 레인보우: 별표 포함 or UR
match: (r) => r.includes("★") || ["UR"].includes(r),
background:
"linear-gradient(45deg, rgba(204, 75, 149, 0.8) 10%, rgba(102, 148, 210, 0.8), rgba(113, 194, 228, 0.8), rgba(129, 197, 101, 0.8), rgba(240, 219, 76, 0.8))",
},
{
// ⚙ 메탈: SP / PcC / PcU / PcR
match: (r) => ["SP", "PcC", "PcU", "PcR"].includes(r),
background:
"linear-gradient(90deg, rgba(139,155,175,0.85), rgba(231,239,247,0.9) 50%, rgba(139,155,175,0.85))",
},
{
// 🟡 SR 계열
match: (r) => ["SR", "PcSR"].includes(r),
background: "#F2F320",
},
];
function applyRarityStyle(rarityDiv, rarity) {
// 기본 배경
rarityDiv.style.backgroundColor = "rgba(255, 255, 255, 0.8)";
for (const rule of RARITY_STYLE_RULES) {
if (rule.match(rarity)) {
rarityDiv.style.background = rule.background;
break; // 첫 매칭 규칙만 적용
}
}
}
// 4. 카드 목록 표시 및 업데이트
function displayCardList(cardList) {
const cardGrid = document.getElementById("card-grid");
cardGrid.innerHTML = "";
// 광고 배너 추가
// const totalCards = cardList.length;
// let adCount = 0;
// if (totalCards >= 50) {
// adCount = Math.floor(totalCards / 150) + 1;
// }
// const adIndices = [];
// if (adCount > 0) {
// const segmentSize = Math.floor(totalCards / adCount);
// for (let i = 0; i < adCount; i++) {
// const start = i * segmentSize;
// const end = (i === adCount - 1) ? totalCards - 1 : (i + 1) * segmentSize - 1;
// const randIndex = Math.floor(Math.random() * (end - start + 1)) + start;
// adIndices.push(randIndex);
// }
// }
cardList.forEach((card, index) => {
const cardContainer = document.createElement("div");
cardContainer.className =
"cardContainer group relative z-10 hover:z-40 select-none flex flex-col";
cardContainer.setAttribute("data-imgsrc", card.imgSrc);
const imgSrc = `images/${seriesKey}/${card.imgSrc.split("/").pop()}`;
const img = document.createElement("img");
img.src = imgSrc;
img.alt = "";
img.className =
"h-full w-full object-contain object-center transition-opacity lg:h-full lg:w-full";
img.onerror = () => handleImageError(card, img);
const imageContainer = document.createElement("div");
imageContainer.className =
"card_image cursor-pointer aspect-w-1 w-full mb-2 lg:mb-3 xl:mb-4 rounded-md lg:aspect-none";
imageContainer.appendChild(img);
imageContainer.addEventListener("click", () => {
showOverlay(card, index, cardList);
});
const countDiv = document.createElement("div");
countDiv.className = "absolute top-0 right-0";
const infoDiv = document.createElement("div");
infoDiv.className = "flex justify-between";
if (card.rarity) {
const rarityDiv = document.createElement("div");
rarityDiv.className =
"card-rarity font-bold inline-flex items-center rounded-full px-2 text-xs ring-1 ring-inset ring-gray-500/10";
rarityDiv.textContent = card.rarity;
applyRarityStyle(rarityDiv, card.rarity.trim());
infoDiv.appendChild(rarityDiv);
}
const numberDiv = document.createElement("div");
numberDiv.className = "flex items-center text-xs";
numberDiv.textContent =
card.color === "AP" ? "ACTION POINT" : card.Number.slice(-5);
infoDiv.appendChild(numberDiv);
const countControlDiv = document.createElement("div");
countControlDiv.className = "pt-1 flex justify-between z-10";
const decrementButton = document.createElement("button");
decrementButton.textContent = "-";
decrementButton.className =
"decrementButton cursor-pointer rounded-lg bg-black w-8 h-8 text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:z-10 disabled:opacity-0 disabled:cursor-not-allowed touch-manipulation";
if (card.count == 0) {
decrementButton.classList.add("opacity-0", "cursor-not-allowed");
}
decrementButton.addEventListener("click", (event) =>
decrementCount(card, event)
);
countControlDiv.appendChild(decrementButton);
const countSpan = document.createElement("span");
countSpan.textContent = card.count;
countSpan.className = "mx-1 w-8 text-center pt-1";
countControlDiv.appendChild(countSpan);
const incrementButton = document.createElement("button");
incrementButton.textContent = "+";
incrementButton.className =
"incrementButton cursor-pointer rounded-lg bg-black w-8 h-8 text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-0 disabled:cursor-not-allowed touch-manipulation";
if (card.count == 4) {
incrementButton.classList.add("opacity-0", "cursor-not-allowed");
}
incrementButton.addEventListener("click", (event) =>
incrementCount(card, event)
);
countControlDiv.appendChild(incrementButton);
const keyCardButton = document.createElement("button");
keyCardButton.textContent = "KEY CARD";
keyCardButton.className =
"keyCardButton cursor-pointer rounded-lg bg-white w-full px-2 py-1 mt-1 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50";
if (card.key) {
keyCardButton.classList.add("opacity-100");
keyCardButton.classList.remove("opacity-50");
} else {
keyCardButton.classList.add("opacity-50");
keyCardButton.classList.remove("opacity-100");
}
keyCardButton.addEventListener("click", (event) =>
toggleKeyCard(card, event)
);
cardContainer.appendChild(imageContainer);
cardContainer.appendChild(countDiv);
cardContainer.appendChild(infoDiv);
cardContainer.appendChild(countControlDiv);
cardContainer.appendChild(keyCardButton);
cardGrid.appendChild(cardContainer);
// 광고 프레임
// const adFrames = [
// `<iframe src="https://ads-partners.coupang.com/widgets.html?id=915488&template=carousel&trackingCode=AF6561083&subId=&width=200&height=360&tsource=" class="absolute top-0 left-0 w-full h-full" frameborder="0" scrolling="no" referrerpolicy="unsafe-url" browsingtopics></iframe>`,
// `<iframe src="https://ads-partners.coupang.com/widgets.html?id=915505&template=carousel&trackingCode=AF6561083&subId=&width=200&height=360&tsource=" class="absolute top-0 left-0 w-full h-full" frameborder="0" scrolling="no" referrerpolicy="unsafe-url" browsingtopics></iframe>`,
// `<iframe src="https://ads-partners.coupang.com/widgets.html?id=915509&template=carousel&trackingCode=AF6561083&subId=&width=200&height=360&tsource=" class="absolute top-0 left-0 w-full h-full" frameborder="0" scrolling="no" referrerpolicy="unsafe-url" browsingtopics></iframe>`,
// `<iframe src="https://ads-partners.coupang.com/widgets.html?id=915510&template=carousel&trackingCode=AF6561083&subId=&width=200&height=360&tsource=" class="absolute top-0 left-0 w-full h-full" frameborder="0" scrolling="no" referrerpolicy="unsafe-url" browsingtopics></iframe>`,
// `<iframe src="https://ads-partners.coupang.com/widgets.html?id=915514&template=carousel&trackingCode=AF6561083&subId=&width=200&height=360&tsource=" class="absolute top-0 left-0 w-full h-full" frameborder="0" scrolling="no" referrerpolicy="unsafe-url" browsingtopics></iframe>`
// ];
// if (adIndices.includes(index)) {
// console.log("coupang:", index);
// const bannerContainer = document.createElement("div");
// bannerContainer.className = "relative w-full h-full flex flex-col my-2";
// const adIndex = adIndices.indexOf(index) % adFrames.length;
// bannerContainer.innerHTML = adFrames[adIndex];
// cardGrid.appendChild(bannerContainer);
// }
});
function showOverlay(card, index, cardList) {
console.log(card, index, cardList);
const overlay = document.getElementById("imageOverlay");
const img = overlay.querySelector("img");
const imgSrc = `images/${seriesKey}/${card.imgSrc.split("/").pop()}`;
let imageLoaded = false;
img.onload = () => {
imageLoaded = true;
};
img.onerror = () => {
handleOverlayImageError(img);
imageLoaded = true;
};
img.src = imgSrc;
overlay.style.display = "flex";
const handleKeyDown = (event) => {
if (event.key === "ArrowLeft" && imageLoaded) {
index = (index - 1 + cardList.length) % cardList.length;
imageLoaded = false;
showOverlay(cardList[index], index, cardList);
event.preventDefault();
} else if (event.key === "ArrowRight" && imageLoaded) {
index = (index + 1) % cardList.length;
imageLoaded = false;
showOverlay(cardList[index], index, cardList);
event.preventDefault();
}
};
document.addEventListener("keydown", handleKeyDown);
overlay.onclick = (event) => {
if (event.target === overlay) {
overlay.style.display = "none";
document.removeEventListener("keydown", handleKeyDown);
}
};
}
function handleOverlayImageError(img) {
img.src = "/images/uapr/comingsoon.png";
img.onerror = null;
}
const SearchResultsCounter = document.getElementById(
"SearchResultsCounter"
);
SearchResultsCounter.textContent = cardList.length;
colorButtons.forEach((btn) => {
const color = btn.dataset.color;
if (selectedColors.has(color)) {
btn.style.opacity = 1;
} else {
btn.style.opacity = 0.5;
}
if (selectedColors.size === 0) {
colorButtons[0].style.opacity = 1;
}
});
}
function handleImageError(card, img) {
img.src = "/images/uapr/comingsoon.png";
img.onerror = null;
}
// 5. 카드 개수 조절 및 키 카드 관리
function decrementCount(card, event) {
if (card.count > 0) {
event.stopPropagation();
card.count--;
if (card.count === 0) {
card.key = false;
}
updateCardDisplay(card, document.activeElement);
updateCardCount(card, card.count);
updateLocalStorage();
updateQueryParameters();
}
}
function incrementCount(card, event) {
const maxCount = card.maxCount || 4;
const sameNumberCards = cardList.filter(
(c) => c.Number === card.Number
);
const totalCount = sameNumberCards.reduce((sum, c) => sum + c.count, 0);
if (totalCount < maxCount) {
event.stopPropagation();
card.count++;
updateCardDisplay(card, document.activeElement);
updateCardCount(card, card.count);
updateLocalStorage();
updateQueryParameters();
}
}
function updateCardDisplay(card, element) {
const cardContainers = document.querySelectorAll(
`.cardContainer[data-imgsrc="${card.imgSrc}"]`
);
let targetContainer = null;
cardContainers.forEach((container) => {
targetContainer = container;
});
if (targetContainer) {
const countSpan = targetContainer.querySelector(
"span.mx-1.w-8.text-center.pt-1"
);
if (countSpan) {
countSpan.textContent = card.count;
}
updateButtonState(targetContainer, card);
}
updateLocalStorage();
updateCounters();
}
function updateButtonState(container, card) {
const decrementButton = container.querySelector(
"button.decrementButton"
);
const incrementButton = container.querySelector(
"button.incrementButton"
);
const keyCardButton = container.querySelector("button.keyCardButton");
// 같은 Number를 가진 카드들의 총 개수 계산
const sameNumberCards = cardList.filter(
(c) => c.Number === card.Number
);
const totalCount = sameNumberCards.reduce((sum, c) => sum + c.count, 0);
const maxCount = card.maxCount || 4;
if (decrementButton) {
decrementButton.classList.toggle("opacity-0", card.count === 0);
decrementButton.classList.toggle(
"cursor-not-allowed",
card.count === 0
);
}
if (incrementButton) {
incrementButton.classList.toggle("opacity-0", totalCount >= maxCount);
incrementButton.classList.toggle(
"cursor-not-allowed",
totalCount >= maxCount
);
}
if (keyCardButton) {
keyCardButton.disabled = card.count === 0;
if (card.count === 0) {
card.key = false;
}
keyCardButton.classList.toggle(
"opacity-100",
card.key && card.count > 0
);
keyCardButton.classList.toggle(
"opacity-50",
!card.key || card.count === 0
);
}
// 같은 Number를 가진 모든 카드의 + 버튼 상태 업데이트
sameNumberCards.forEach((sameCard) => {
if (sameCard !== card) {
const otherContainer = document.querySelector(
`.cardContainer[data-imgsrc="${sameCard.imgSrc}"]`
);
if (otherContainer) {
const otherIncrementButton = otherContainer.querySelector(
"button.incrementButton"
);
if (otherIncrementButton) {
otherIncrementButton.classList.toggle(
"opacity-0",
totalCount >= maxCount
);
otherIncrementButton.classList.toggle(
"cursor-not-allowed",
totalCount >= maxCount
);
}
}
}
});
}
function updateCounters() {
let keyCount = 0;
let colorCount = 0;
let finalCount = 0;
let specialCount = 0;
let totalCount = 0;
cardList.forEach((card) => {
if (card.key && card.count > 0) {
keyCount++;
}
if (card.trigger === "COLOR" && card.count > 0) {
colorCount += card.count;
}
if (card.trigger === "FINAL" && card.count > 0) {
finalCount += card.count;
}
if (card.trigger === "SPECIAL" && card.count > 0) {
specialCount += card.count;
}
totalCount += card.count;
});
keyCardCountElement.textContent = keyCount;
colorCardCountElement.textContent = colorCount;
finalCardCountElement.textContent = finalCount;
specialCardCountElement.textContent = specialCount;
totalCardCountElement.textContent = totalCount;
}
function toggleKeyCard(card, event) {
event.stopPropagation();
if (card.count === 0) {
return;
}
const maxKeyCards = 4;
const currentKeyCards = cardList.filter(
(c) => c.key && c.count > 0
).length;
if (card.key) {
card.key = false;
} else if (currentKeyCards < maxKeyCards) {
card.key = true;
}
updateCardDisplay(card, document.activeElement);
updateLocalStorage();
updateQueryParameters();
}
function updateSelectedCards() {
selectedCards = cardList.filter((card) => card.count > 0);
}
function updateCardCount(card, count) {
card.count = count;
updateSelectedCards();
updateLocalStorage();
}
// 6. 로컬 스토리지 업데이트 및 결과 페이지 이동
function updateLocalStorage() {
const queryParams = encodeURIComponent(JSON.stringify(selectedCards));
localStorage.setItem("selectedCards", queryParams);
}
// 7. 검색 및 필터링 기능
searchQueryInput.addEventListener("input", updateCardList);
colorButtons.forEach((button) => {
button.addEventListener("click", () => {
const color = button.dataset.color;
if (color === "All") {
selectedColors.clear();
selectedColors.add("All");
} else {
selectedColors.delete("All");
if (selectedColors.has(color)) {
selectedColors.delete(color);
} else {
selectedColors.add(color);
}
}
if (selectedColors.size === 0) {
selectedColors.add("All");
}
updateCardList();
});
});
function updateCardList() {
const includeBasic = includeBasicCheckbox.checked;
const includeAP = includeAPCheckbox.checked;
const includeParallel = includeParallelCheckbox.checked;
console.log(
`TYPE FILTER - [Basic: ${includeBasic}], [AP: ${includeAP}], [Parallel: ${includeParallel}]`
);
let filteredCardList = cardList;
filteredCardList = filteredCardList.filter((card) => {
if (includeBasic && card.color !== "AP" && !card.parallel)
return true;
if (includeAP && card.color === "AP") return true;
if (includeParallel && card.parallel) return true;
return false;
});
if (!selectedColors.has("All")) {
filteredCardList = filteredCardList.filter((card) => {
if (card.color === "Multi") {
return selectedColors.has("ALL COLOR");
} else {
return selectedColors.has(card.color);
}
});
}
const selectedTrigger = document.querySelector(
'input[name="triggerType"]:checked'
).value;
switch (selectedTrigger) {
case "specialTrigger":
filteredCardList = filteredCardList.filter(
(card) => card.trigger === "SPECIAL"
);
break;
case "colorTrigger":
filteredCardList = filteredCardList.filter(
(card) => card.trigger === "COLOR"
);
break;
case "finalTrigger":
filteredCardList = filteredCardList.filter(
(card) => card.trigger === "FINAL"
);
break;
default:
break;
}
const searchQuery = searchQueryInput.value.toLowerCase();
if (searchQuery) {
filteredCardList = filteredCardList.filter((card) => {
return card.Number.toLowerCase().includes(searchQuery);
});
}
displayCardList(filteredCardList);
}
includeBasicCheckbox.addEventListener("change", updateCardList);
includeAPCheckbox.addEventListener("change", updateCardList);
includeParallelCheckbox.addEventListener("change", updateCardList);
includeAllTriggerRadio.addEventListener("change", updateCardList);
includeSpecialTriggerRadio.addEventListener("change", updateCardList);
includeColorTriggerRadio.addEventListener("change", updateCardList);
includeFinalTriggerRadio.addEventListener("change", updateCardList);
function updateQueryParameters() {
const queryParams = encodeURIComponent(JSON.stringify(selectedCards));
const seriesKey = getQueryParam("series");
const nameKey = getQueryParam("seriesName");
const newUrl = new URL(window.location.href);
newUrl.searchParams.set("cards", queryParams);
window.history.replaceState({}, "", newUrl);
}
</script>
</body>
</html>

44
datas/seriesList.js Normal file
View File

@@ -0,0 +1,44 @@
import title from '../i18n/title.js';
const currentLanguage = localStorage.getItem('lang') || 'ko';
const seriesList = [
{ key: 'ua01', name: title.ua01[currentLanguage] },
{ key: 'ua02', name: title.ua02[currentLanguage] },
{ key: 'ua03', name: title.ua03[currentLanguage] },
{ key: 'ua04', name: title.ua04[currentLanguage] },
{ key: 'ua05', name: title.ua05[currentLanguage] },
{ key: 'ua06', name: title.ua06[currentLanguage] },
{ key: 'ua07', name: title.ua07[currentLanguage] },
{ key: 'ua08', name: title.ua08[currentLanguage] },
{ key: 'ua09', name: title.ua09[currentLanguage] },
{ key: 'ua10', name: title.ua10[currentLanguage] },
{ key: 'ua11', name: title.ua11[currentLanguage] },
{ key: 'ua12', name: title.ua12[currentLanguage] },
{ key: 'ua13', name: title.ua13[currentLanguage] },
{ key: 'ua14', name: title.ua14[currentLanguage] },
{ key: 'ua15', name: title.ua15[currentLanguage] },
{ key: 'ua16', name: title.ua16[currentLanguage] },
{ key: 'ua17', name: title.ua17[currentLanguage] },
{ key: 'ua18', name: title.ua18[currentLanguage] },
{ key: 'ua19', name: title.ua19[currentLanguage] },
{ key: 'ua20', name: title.ua20[currentLanguage] },
{ key: 'ua21', name: title.ua21[currentLanguage] },
{ key: 'ua22', name: title.ua22[currentLanguage] },
{ key: 'ua23', name: title.ua23[currentLanguage] },
{ key: 'ua24', name: title.ua24[currentLanguage] },
{ key: 'ua25', name: title.ua25[currentLanguage] },
{ key: 'ua26', name: title.ua26[currentLanguage] },
{ key: 'ua27', name: title.ua27[currentLanguage] },
{ key: 'ua28', name: title.ua28[currentLanguage] },
{ key: 'ua29', name: title.ua29[currentLanguage] },
{ key: 'ua30', name: title.ua30[currentLanguage] },
{ key: 'ua31', name: title.ua31[currentLanguage] },
{ key: 'ua32', name: title.ua32[currentLanguage] },
{ key: 'ua33', name: title.ua33[currentLanguage] },
{ key: 'ua34', name: title.ua34[currentLanguage] },
{ key: 'ua35', name: title.ua35[currentLanguage] },
{ key: 'ua36', name: title.ua36[currentLanguage] },
];
export default seriesList; // seriesList를 default export

2767
datas/ua01.js Normal file

File diff suppressed because it is too large Load Diff

2911
datas/ua02.js Normal file

File diff suppressed because it is too large Load Diff

2749
datas/ua03.js Normal file

File diff suppressed because it is too large Load Diff

4030
datas/ua04.js Normal file

File diff suppressed because it is too large Load Diff

2871
datas/ua05.js Normal file

File diff suppressed because it is too large Load Diff

1618
datas/ua06.js Normal file

File diff suppressed because it is too large Load Diff

2730
datas/ua07.js Normal file

File diff suppressed because it is too large Load Diff

2819
datas/ua08.js Normal file

File diff suppressed because it is too large Load Diff

1640
datas/ua09.js Normal file

File diff suppressed because it is too large Load Diff

2728
datas/ua10.js Normal file

File diff suppressed because it is too large Load Diff

1689
datas/ua11.js Normal file

File diff suppressed because it is too large Load Diff

1759
datas/ua12.js Normal file

File diff suppressed because it is too large Load Diff

1608
datas/ua13.js Normal file

File diff suppressed because it is too large Load Diff

1658
datas/ua14.js Normal file

File diff suppressed because it is too large Load Diff

2954
datas/ua15.js Normal file

File diff suppressed because it is too large Load Diff

1708
datas/ua16.js Normal file

File diff suppressed because it is too large Load Diff

1648
datas/ua17.js Normal file

File diff suppressed because it is too large Load Diff

1759
datas/ua18.js Normal file

File diff suppressed because it is too large Load Diff

1710
datas/ua19.js Normal file

File diff suppressed because it is too large Load Diff

1688
datas/ua20.js Normal file

File diff suppressed because it is too large Load Diff

1726
datas/ua21.js Normal file

File diff suppressed because it is too large Load Diff

1177
datas/ua22.js Normal file

File diff suppressed because it is too large Load Diff

2777
datas/ua23.js Normal file

File diff suppressed because it is too large Load Diff

1627
datas/ua24.js Normal file

File diff suppressed because it is too large Load Diff

1196
datas/ua25.js Normal file

File diff suppressed because it is too large Load Diff

1317
datas/ua26.js Normal file

File diff suppressed because it is too large Load Diff

1667
datas/ua27.js Normal file

File diff suppressed because it is too large Load Diff

1226
datas/ua28.js Normal file

File diff suppressed because it is too large Load Diff

3109
datas/ua29.js Normal file

File diff suppressed because it is too large Load Diff

2859
datas/ua30.js Normal file

File diff suppressed because it is too large Load Diff

1699
datas/ua31.js Normal file

File diff suppressed because it is too large Load Diff

1178
datas/ua32.js Normal file

File diff suppressed because it is too large Load Diff

1246
datas/ua33.js Normal file

File diff suppressed because it is too large Load Diff

1187
datas/ua34.js Normal file

File diff suppressed because it is too large Load Diff

1666
datas/ua35.js Normal file

File diff suppressed because it is too large Load Diff

1748
datas/ua36.js Normal file

File diff suppressed because it is too large Load Diff

1688
datas/ua37.js Normal file

File diff suppressed because it is too large Load Diff

1238
datas/ua38.js Normal file

File diff suppressed because it is too large Load Diff

1217
datas/ua39.js Normal file

File diff suppressed because it is too large Load Diff

1688
datas/ua40.js Normal file

File diff suppressed because it is too large Load Diff

1698
datas/ua41.js Normal file

File diff suppressed because it is too large Load Diff

1778
datas/ua42.js Normal file

File diff suppressed because it is too large Load Diff

1198
datas/ua43.js Normal file

File diff suppressed because it is too large Load Diff

1709
datas/ua44.js Normal file

File diff suppressed because it is too large Load Diff

1397
datas/ua45.js Normal file

File diff suppressed because it is too large Load Diff

1348
datas/ua46.js Normal file

File diff suppressed because it is too large Load Diff

1779
datas/ua47.js Normal file

File diff suppressed because it is too large Load Diff

1007
datas/ua99 sample mini.js Normal file

File diff suppressed because it is too large Load Diff

1318
datas/ua99 sample.js Normal file

File diff suppressed because it is too large Load Diff

54
datas/uapr.js Normal file
View File

@@ -0,0 +1,54 @@
const uaprData = [
{
imgSrc: '/uapr/UAPR_2023-AP01.png',
Number: 'UAPR/2023-AP01',
count: 0,
key: false,
color: 'AP',
parallel: false,
rarity: '',
trigger: null,
},
{
imgSrc: '/uapr/UAPR_2023-AP02.png',
Number: 'UAPR/2023-AP02',
count: 0,
key: false,
color: 'AP',
parallel: false,
rarity: '',
trigger: null,
},
{
imgSrc: '/uapr/UAPR_2023-AP03.png',
Number: 'UAPR/2023-AP03',
count: 0,
key: false,
color: 'AP',
parallel: false,
rarity: '',
trigger: null,
},
{
imgSrc: '/uapr/UAPR_2023-AP04.png',
Number: 'UAPR/2023-AP04',
count: 0,
key: false,
color: 'AP',
parallel: false,
rarity: '',
trigger: null,
},
{
imgSrc: '/uapr/UAPR_2023-AP05.png',
Number: 'UAPR/2023-AP05',
count: 0,
key: false,
color: 'AP',
parallel: false,
rarity: '',
trigger: null,
},
];
export default uaprData;

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

60
i18n/i18n.js Normal file
View File

@@ -0,0 +1,60 @@
// 계층구조 사용시
async function loadTranslations(lang) {
try {
const response = await fetch(`/i18n/translations.${lang}.json`);
if (!response.ok) {
throw new Error(`Failed to load translations for ${lang}`);
}
return await response.json();
} catch (error) {
console.error(error);
return {};
}
}
async function localizePage(lang) {
const translations = await loadTranslations(lang);
const elements = document.querySelectorAll('[data-i18n]');
elements.forEach(element => {
const key = element.dataset.i18n;
const localizedText = findNestedValue(translations, key);
if (localizedText) {
element.textContent = localizedText;
}
});
}
function findNestedValue(obj, key) {
if (obj.hasOwnProperty(key)) {
return obj[key];
}
for (const prop in obj) {
if (typeof obj[prop] === 'object' && obj[prop] !== null) {
const result = findNestedValue(obj[prop], key);
if (result) {
return result;
}
}
}
return null;
}
document.addEventListener('DOMContentLoaded', async () => {
const storedLang = localStorage.getItem('lang');
if (storedLang) {
await localizePage(storedLang);
return;
}
const urlParams = new URLSearchParams(window.location.search);
const queryLang = urlParams.get('lang');
const lang = queryLang || 'ko';
localStorage.setItem('lang', lang);
await localizePage(lang);
});
// 계층구조 미사용시 코드는 주석 처리된 상태로 유지

91
i18n/translations.en.json Normal file
View File

@@ -0,0 +1,91 @@
{
"all": "All",
"metaDeck": "Meta Deck",
"titlePrompt": "Please select a title",
"selectTitle": "Select Title",
"deckName": "Deck Name",
"deckNamePlaceHolder": "Please enter the name",
"myDeckHistory": "My Deck History",
"notHistory": "No saved history",
"preview": "Preview",
"back": "Back",
"close": "Close",
"reset": "Reset",
"dataBackup": "Data Backup",
"dataRecovery": "Data Recovery",
"saveAsImage": "Save as Image",
"selectDeckTemplate": "Select Deck Template",
"nowSaving": "Now Saving ...",
"search": "Search",
"searchPlaceHolder": "ex) 008 ...",
"noSearchResults": "No search results.",
"scrollingNotice": "This site is optimized for PC (Chrome browser).",
"cardTypeTitle": "Cards Type",
"includeParallel": "Show parallel cards",
"includeActionPoint": "Show AP Cards",
"onlyParallel": "Show only parallel cards",
"onlyActionPoint": "Show only AP Cards",
"triggerTypeTitle": "Trigger Type",
"includeAllTrigger": "ALL",
"includeColorTrigger": "COLOR",
"includeFinalTrigger": "FINAL",
"includeSpecialTrigger": "SPECIAL",
"resetCountConfirm": "Anything written to this set will be deleted. Do you still want to reset it?",
"SearchResults": "Search Results",
"SearchResultsCounter": "Cards",
"limitOverAlert": "There are cards exceeding the quantity limit. Should we proceed as is?",
"highQualityTitle": "Save in high definition",
"highQualityDesc": "※ Caution: Quality is doubled, file size is quadrupled!",
"previewMessage1": "Preview is not supported on mobile.",
"previewMessage2": "After saving the image, please check.",
"series": {
"ua01": "Code Geass: Lelouch of the Rebellion",
"ua02": "Jujutsu Kaisen",
"ua03": "HUNTER×HUNTER",
"ua04": "THE iDOLM@STER SHINY COLORS",
"ua05": "Demon Slayer: Kimetsu no Yaiba",
"ua06": "Tales of ARISE",
"ua07": "That Time I Got Reincarnated as a Slime",
"ua08": "Bleach: Thousand-Year Blood War",
"ua09": "Me & Roboco",
"ua10": "My Hero Academia",
"ua11": "Gintama",
"ua12": "Blue Lock",
"ua13": "TEKKEN 7",
"ua14": "Dr.STONE",
"ua15": "Sword Art Online",
"ua16": "SYNDUALITY Noir",
"ua17": "Toriko",
"ua18": "GODDESS OF VICTORYNIKKE",
"ua19": "Haikyu!!",
"ua20": "BLACK CLOVER",
"ua21": "Yu Yu Hakusho",
"ua22": "GAMERA -Rebirth-",
"ua23": "Attack on Titan",
"ua24": "SHY",
"ua25": "Undead Unluck",
"ua26": "The 100 Girlfriends Who Really, Really, Really, Really Love You",
"ua27": "Gakuen iDOLM@STER",
"ua28": "Kaiju No.8",
"ua29": "Kamen Rider",
"ua30": "Arknights",
"ua31": "Puella Magi Madoka Magica",
"ua32": "Shangri-La Frontier",
"ua33": "2.5 Dimensional Seduction",
"ua34": "CODE GEASS: Roze of the Recapture",
"ua35": "ONE-PUNCH MAN",
"ua36": "Macross",
"ua37": "Fullmetal Alchemist",
"ua38": "WIND BREAKER",
"ua39": "ULTIMATE MUSCLE",
"ua40": "Re:ZERO -Starting Life in Another World-",
"ua41": "Rurouni Kenshin: Meiji Kenkaku Romantan",
"ua42": "Monogatari Series",
"ua43": "SAKAMOTO DAYS",
"ua44": "Rebuild of Evangelion",
"ua45": "To Love Ru",
"ua46": "Kagurabachi",
"ua47": "Tokyo Ghoul"
},
"uapr": "UNION ARENA"
}

107
i18n/translations.ja.json Normal file
View File

@@ -0,0 +1,107 @@
{
"all": "全て",
"metaDeck": "メタデッキ",
"titlePrompt": "タイトルを選択してください",
"selectTitle": "タイトルを選択",
"deckName": "デッキ名",
"deckNamePlaceHolder": "名前を入力してください",
"myDeckHistory": "私のデッキ記録",
"notHistory": "保存された記録はありません",
"close": "CLOSE",
"reset": "リセット",
"dataBackup": "データバックアップ",
"dataRecovery": "データ復元",
"selectDeckTemplate": "Select Deck Template",
"nowSaving": "保存中...",
"search": "検索",
"searchPlaceHolder": "ex) 008 ...",
"noSearchResults": "検索結果がありません。",
"scrollingNotice": "このサイトはPCクロームブラウザに最適化されています。",
"cardTypeTitle": "カード種類",
"onlyParallel": "パラレルカードのみを表示",
"onlyActionPoint": "APカードのみを表示",
"triggerTypeTitle": "トリガー効果",
"includeAllTrigger": "ALL",
"includeColorTrigger": "COLOR",
"includeFinalTrigger": "FINAL",
"includeSpecialTrigger": "SPECIAL",
"resetCountConfirm": "このセットに記録されている内容はすべて削除されます。\nそれでもリセットしますか",
"limitOverAlert": "制限数を超えるカードがあります。このまま続行しますか?",
"highQualityTitle": "高画質で保存する",
"highQualityDesc": "※ 注意: 品質は2倍、容量は4倍です",
"previewMessage1": "モバイルでのプレビューはサポートされていません。",
"previewMessage2": "画像を保存した後、確認してください。",
"series": {
"ua01": "コードギアス 反逆のルルーシュ",
"ua02": "呪術廻戦",
"ua03": "HUNTER×HUNTER",
"ua04": "アイドルマスター シャイニーカラーズ",
"ua05": "鬼滅の刃",
"ua06": "Tales of ARISE",
"ua07": "転生したらスライムだった件",
"ua08": "BLEACH 千年血戦篇",
"ua09": "僕とロボコ",
"ua10": "僕のヒーローアカデミア",
"ua11": "銀魂",
"ua12": "ブルーロック",
"ua13": "鉄拳7",
"ua14": "Dr.STONE",
"ua15": "ソードアート・オンライン",
"ua16": "SYNDUALITY Noir",
"ua17": "トリコ",
"ua18": "勝利の女神NIKKE",
"ua19": "ハイキュー‼",
"ua20": "ブラッククローバー",
"ua21": "幽☆遊☆白書",
"ua22": "GAMERA -Rebirth-",
"ua23": "進撃の巨人",
"ua24": "SHY",
"ua25": "アンデッドアンラック",
"ua26": "君のことが大大大大大好きな100人の彼女",
"ua27": "学園アイドルマスター",
"ua28": "怪獣8号",
"ua29": "仮面ライダー",
"ua30": "アークナイツ",
"ua31": "魔法少女まどか☆マギカ",
"ua32": "シャングリラ・フロンティア",
"ua33": "2.5次元の誘惑",
"ua34": "コードギアス 奪還のロゼ",
"ua35": "ワンパンマン",
"ua36": "マクロス",
"ua37": "鋼の錬金術師",
"ua38": "WIND BREAKER",
"ua39": "キン肉マン",
"ua40": "Re:ゼロから始める異世界生活",
"ua41": "るろうに剣心 -明治剣客浪漫譚-",
"ua42": "〈物語〉シリーズ",
"ua43": "SAKAMOTO DAYS",
"ua44": "ヱヴァンゲリヲン新劇場版",
"ua45": "To LOVEる-とらぶる-",
"ua46": "カグラバチ",
"ua47": "東京喰種トーキョーグール"
},
"uapr": "UNION ARENA",
"CardList": {
"ResultsCounter": {
"SearchResults": "検索結果",
"SearchResultsCounter": "件"
},
"CardType": {
"includeBasic": "기본 카드",
"includeParallel": "パラレルカード",
"includeActionPoint": "APカード"
},
"TriggerType": {
"includeAllTrigger": "모든 트리거",
"includeColorTrigger": "COLOR",
"includeSpecialTrigger": "SPECIAL",
"includeFinalTrigger": "FINAL"
},
"makeDeckList": "덱 리스트 만들기"
},
"Result": {
"preview": "プレビュー",
"back": "戻る",
"saveAsImage": "画像として保存"
}
}

103
i18n/translations.ko.json Normal file
View File

@@ -0,0 +1,103 @@
{
"all": "전체",
"metaDeck": "메타 덱",
"titlePrompt": "작품을 선택해주세요",
"selectTitle": "작품 선택",
"deckName": "덱 이름",
"deckNamePlaceHolder": "이름을 입력해주세요",
"myDeckHistory": "나의 덱 기록",
"notHistory": "저장된 기록이 없습니다",
"close": "닫기",
"reset": "초기화",
"dataBackup": "데이터 백업",
"dataRecovery": "데이터 복구",
"selectDeckTemplate": "덱 템플릿 선택",
"nowSaving": "이미지로 저장 중 ...",
"search": "검색",
"searchPlaceHolder": "예) 008 ...",
"noSearchResults": "검색 결과가 없습니다.",
"scrollingNotice": "본 사이트는 PC(크롬 브라우저)에 최적화 되어있습니다.",
"cardTypeTitle": "카드 종류",
"onlyParallel": "패러렐 카드만 표시",
"onlyActionPoint": "액션 포인트 카드만 표시",
"triggerTypeTitle": "트리거 효과",
"resetCountConfirm": "이 세트에 기록된 모든 내용은 삭제됩니다. 그래도 초기화하시겠습니까?",
"limitOverAlert": "제한 수량을 초과하는 카드가 있습니다. 이대로 계속 진행할까요?",
"highQualityTitle": "고화질로 저장하기",
"highQualityDesc": "※ 주의: 품질은 2배, 용량은 4배!",
"previewMessage1": "모바일에서는 미리보기를 지원하지 않습니다.",
"previewMessage2": "이미지를 저장한 후 확인해주세요.",
"series": {
"ua01": "코드 기어스: 반역의 를르슈",
"ua02": "주술회전",
"ua03": "HUNTER×HUNTER",
"ua04": "아이돌 마스터 샤이니 컬러즈",
"ua05": "귀멸의칼날",
"ua06": "Tales of ARISE",
"ua07": "전생했더니 슬라임이었던 건에 대하여",
"ua08": "BLEACH 천년혈전 편",
"ua09": "나와 로보코",
"ua10": "나의 히어로 아카데미아",
"ua11": "은혼",
"ua12": "블루 록",
"ua13": "철권7",
"ua14": "Dr.STONE",
"ua15": "소드 아트 온라인",
"ua16": "신듀얼리티 느와르",
"ua17": "토리코",
"ua18": "승리의여신NIKKE",
"ua19": "하이큐ー‼",
"ua20": "블랙 클로버",
"ua21": "유유백서",
"ua22": "가메라 -리버스-",
"ua23": "진격의 거인",
"ua24": "SHY",
"ua25": "언데드 언럭",
"ua26": "너를 너무너무너무너무 좋아하는 100명의 그녀",
"ua27": "학원 아이돌 마스터",
"ua28": "괴수 8호",
"ua29": "가면 라이더",
"ua30": "명일방주",
"ua31": "마법소녀 마도카☆마기카",
"ua32": "샹그릴라 프론티어",
"ua33": "2.5차원의 유혹",
"ua34": "코드기어스 탈환의로제",
"ua35": "원펀맨",
"ua36": "마크로스",
"ua37": "강철의 연금술사",
"ua38": "WIND BREAKER",
"ua39": "근육맨",
"ua40": "Re: 제로부터 시작하는 이세계 생활",
"ua41": "바람의 검심 -메이지 검객 낭만기-",
"ua42": "모노가타리 시리즈",
"ua43": "사카모토 데이즈",
"ua44": "에반게리온 신극장판",
"ua45": "To LOVE 트러블",
"ua46": "카구라바치",
"ua47": "도쿄 구울"
},
"uapr": "UNION ARENA",
"CardList": {
"ResultsCounter": {
"SearchResults": "검색결과",
"SearchResultsCounter": "건"
},
"CardType": {
"includeBasic": "기본 카드",
"includeParallel": "패러렐 카드",
"includeActionPoint": "액션 포인트(AP)"
},
"TriggerType": {
"includeAllTrigger": "모든 트리거",
"includeColorTrigger": "COLOR",
"includeSpecialTrigger": "SPECIAL",
"includeFinalTrigger": "FINAL"
},
"makeDeckList": "덱 리스트 만들기"
},
"Result": {
"preview": "미리보기",
"back": "돌아가기",
"saveAsImage": "이미지로 저장"
}
}

BIN
images/logo_unionarena.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Some files were not shown because too many files have changed in this diff Show More