/**
* 배경 씬 라이브러리 JavaScript
* Unity에서 업로드된 JSON 데이터를 기반으로 배경 목록을 표시
*/
(function() {
'use strict';
// 데이터 파일 경로
const DATA_PATH = 'data/backgrounds.json';
// 상태
let backgroundsData = [];
let filteredData = [];
let currentTag = 'all';
let currentView = 'grid';
let searchQuery = '';
// DOM 요소
const elements = {
grid: document.getElementById('backgroundsGrid'),
filterTags: document.getElementById('filterTags'),
searchInput: document.getElementById('searchInput'),
totalCount: document.getElementById('totalCount'),
filteredCount: document.getElementById('filteredCount'),
lastUpdated: document.getElementById('lastUpdated'),
noData: document.getElementById('noData'),
noResults: document.getElementById('noResults'),
imageModal: document.getElementById('imageModal'),
modalImage: document.getElementById('modalImage'),
modalTitle: document.getElementById('modalTitle'),
modalCategory: document.getElementById('modalCategory'),
modalTags: document.getElementById('modalTags')
};
/**
* 초기화
*/
async function init() {
await loadData();
setupEventListeners();
}
/**
* 데이터 로드
*/
async function loadData() {
try {
const response = await fetch(DATA_PATH + '?t=' + Date.now());
if (!response.ok) {
throw new Error('데이터를 찾을 수 없습니다');
}
const data = await response.json();
backgroundsData = data.backgrounds || [];
// 마지막 업데이트 시간 표시
if (data.lastUpdated) {
const date = new Date(data.lastUpdated);
elements.lastUpdated.textContent = `마지막 업데이트: ${formatDate(date)}`;
}
// 태그 필터 생성
createTagFilters();
// 통계 업데이트
elements.totalCount.textContent = backgroundsData.length;
// 데이터 렌더링
filterAndRender();
} catch (error) {
console.error('데이터 로드 실패:', error);
showNoData();
}
}
/**
* 태그 필터 버튼 생성
*/
function createTagFilters() {
// 모든 태그 수집
const allTags = new Set();
backgroundsData.forEach(bg => {
if (bg.tags && Array.isArray(bg.tags)) {
bg.tags.forEach(tag => allTags.add(tag));
}
});
// 기존 태그 버튼 제거 (전체 버튼 제외)
const existingTags = elements.filterTags.querySelectorAll('.filter-tag:not([data-tag="all"])');
existingTags.forEach(tag => tag.remove());
// 태그 버튼 생성
allTags.forEach(tag => {
const btn = document.createElement('button');
btn.className = 'filter-tag';
btn.dataset.tag = tag;
btn.textContent = tag;
btn.addEventListener('click', () => setTagFilter(tag));
elements.filterTags.appendChild(btn);
});
}
/**
* 이벤트 리스너 설정
*/
function setupEventListeners() {
// 검색
elements.searchInput.addEventListener('input', debounce((e) => {
searchQuery = e.target.value.toLowerCase();
filterAndRender();
}, 300));
// 전체 태그 필터
const allTagBtn = elements.filterTags.querySelector('[data-tag="all"]');
if (allTagBtn) {
allTagBtn.addEventListener('click', () => setTagFilter('all'));
}
// 뷰 전환
document.querySelectorAll('.view-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.view-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentView = btn.dataset.view;
updateViewMode();
});
});
// 모달 닫기
elements.imageModal.querySelector('.modal-overlay').addEventListener('click', closeModal);
elements.imageModal.querySelector('.modal-close').addEventListener('click', closeModal);
// ESC 키로 모달 닫기
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeModal();
});
}
/**
* 태그 필터 설정
*/
function setTagFilter(tag) {
currentTag = tag;
// 버튼 활성화 상태 업데이트
document.querySelectorAll('.filter-tag').forEach(btn => {
btn.classList.toggle('active', btn.dataset.tag === tag);
});
filterAndRender();
}
/**
* 필터링 및 렌더링
*/
function filterAndRender() {
// 필터링
filteredData = backgroundsData.filter(bg => {
// 태그 필터
if (currentTag !== 'all') {
if (!bg.tags || !bg.tags.includes(currentTag)) {
return false;
}
}
// 검색 필터
if (searchQuery) {
const searchTarget = `${bg.sceneName} ${bg.categoryName} ${(bg.tags || []).join(' ')}`.toLowerCase();
if (!searchTarget.includes(searchQuery)) {
return false;
}
}
return true;
});
// 통계 업데이트
elements.filteredCount.textContent = filteredData.length;
// 렌더링
render();
}
/**
* 카드 렌더링
*/
function render() {
// 로딩/에러 상태 숨기기
const loadingPlaceholder = elements.grid.querySelector('.loading-placeholder');
if (loadingPlaceholder) {
loadingPlaceholder.remove();
}
elements.noData.style.display = 'none';
elements.noResults.style.display = 'none';
// 데이터 없음
if (backgroundsData.length === 0) {
elements.grid.innerHTML = '';
showNoData();
return;
}
// 검색 결과 없음
if (filteredData.length === 0) {
elements.grid.innerHTML = '';
elements.noResults.style.display = 'block';
return;
}
// 카드 생성
elements.grid.innerHTML = filteredData.map(bg => createCard(bg)).join('');
// 카드 클릭 이벤트
elements.grid.querySelectorAll('.background-card').forEach((card, index) => {
card.addEventListener('click', () => openModal(filteredData[index]));
});
// 뷰 모드 적용
updateViewMode();
}
/**
* 카드 HTML 생성
*/
function createCard(bg) {
const thumbnailHtml = bg.thumbnailUrl
? ``
: `