import NSW_DB from '../db/nsw.db.js'; document.addEventListener('DOMContentLoaded', () => { const gameList = document.getElementById('gameList'); const gameCount = document.getElementById('gameCount'); const loading = document.getElementById('loading'); const languageRadios = document.querySelectorAll('input[name="language"]'); // 언어별 UI 텍스트 const uiTexts = { ko: { title: 'Switch DB', languageSelect: '언어 선택', languageDescription: '선택한 언어로 표시됩니다', korean: '한국어', japanese: '일본어', count: '개수', loading: '로딩중...', tableHeaders: { title: '제목', info: '정보', status: '상태', role: '역할', location: '지역' }, sortOptions: { sortByNoDesc: '순번 최신순', sortByNo: '순번 과거순', sortByDateDesc: '발매일 최신순', sortByDate: '발매일 과거순', sortByPurchaseDateDesc: '구매일 최신순', sortByPurchaseDate: '구매일 과거순', sortByRandom: '무작위', }, filter: { reset: '필터 초기화', koreanSupport: '한국어 지원', koreanNotSupport: '한국어 미지원', }, }, ja: { title: 'ゲーム一覧', languageSelect: '言語選択', languageDescription: '選択した言語で表示されます', korean: '韓国語', japanese: '日本語', count: '件数', loading: '読み込み中...', tableHeaders: { title: 'タイトル', info: '情報', status: '状態', role: '役割', location: '地域' }, sortOptions: { sortByNoDesc: '番号降順', sortByNo: '番号昇順', sortByDateDesc: '発売日降順', sortByDate: '発売日昇順', sortByPurchaseDateDesc: '購入日降順', sortByPurchaseDate: '購入日昇順', sortByRandom: 'ランダム', }, filter: { reset: 'フィルターリセット', koreanSupport: '韓国語対応', koreanNotSupport: '韓国語非対応', }, }, }; // 필터 상태 관리 객체 const filterState = { language: 'ko', filters: { language: [], status: [], country: [], cero: [], }, sortBy: 'sortByNoDesc', // 기본 정렬 옵션 }; // 정렬 옵션 정의 const sortOptions = [ { name: '순번 최신순', value: 'sortByNoDesc' }, { name: '순번 과거순', value: 'sortByNo' }, { name: '발매일 최신순', value: 'sortByDateDesc' }, { name: '발매일 과거순', value: 'sortByDate' }, { name: '구매일 최신순', value: 'sortByPurchaseDateDesc' }, { name: '구매일 과거순', value: 'sortByPurchaseDate' }, { name: '무작위', value: 'sortByRandom' }, ]; // UI 텍스트 업데이트 함수 function updateUITexts() { const texts = uiTexts[filterState.language]; // 제목 업데이트 document.querySelector('h1').textContent = texts.title; // 언어 선택 섹션 업데이트 document.querySelector('label.text-base').textContent = texts.languageSelect; document.querySelector('p.text-sm').textContent = texts.languageDescription; document.querySelector('label[for="ko"]').textContent = texts.korean; document.querySelector('label[for="ja"]').textContent = texts.japanese; // 테이블 헤더 업데이트 const headers = document.querySelectorAll('th'); headers[0].textContent = texts.tableHeaders.title; headers[1].textContent = texts.tableHeaders.info; headers[2].textContent = texts.tableHeaders.status; headers[3].textContent = texts.tableHeaders.role; headers[4].textContent = texts.tableHeaders.location; // 로딩 텍스트 업데이트 loading.textContent = texts.loading; // 필터 텍스트 업데이트 document.getElementById('resetFilters').textContent = texts.filter.reset; document.querySelector('label[for="korean-support"]').textContent = texts.filter.koreanSupport; document.querySelector('label[for="korean-not-support"]').textContent = texts.filter.koreanNotSupport; } // 언어 변경 이벤트 리스너 languageRadios.forEach(radio => { radio.addEventListener('change', e => { filterState.language = e.target.value; updateUITexts(); renderGames(); }); }); // 언어 변환 함수 function convertLanguage(language) { if (!language) return ''; if (filterState.language !== 'ko') return language; const languages = language.split(','); const koreanLanguages = []; for (let i = 0; i < languages.length; i++) { switch (languages[i].trim()) { case '日本語': koreanLanguages.push('일본어'); break; case '英語': koreanLanguages.push('영어'); break; case '韓国語': koreanLanguages.push('한국어'); break; case 'フランス語': koreanLanguages.push('프랑스어'); break; case 'ドイツ語': koreanLanguages.push('독일어'); break; case 'イタリア語': koreanLanguages.push('이탈리아어'); break; case 'スペイン語': koreanLanguages.push('스페인어'); break; case 'ロシア語': koreanLanguages.push('러시아어'); break; case 'オランダ語': koreanLanguages.push('네덜란드어'); break; case 'ポルトガル語': koreanLanguages.push('포르투칼어'); break; case '中国語 (簡体字)': koreanLanguages.push('중국어 (간체)'); break; case '中国語 (繁体字)': koreanLanguages.push('중국어 (번체)'); break; default: koreanLanguages.push(languages[i]); break; } } return koreanLanguages.join(', '); } // 메이커 변환 함수 function convertMaker(maker) { if (!maker) return ''; if (filterState.language !== 'ko') return maker; const makers = maker.split(','); const koreanMakers = []; for (let i = 0; i < makers.length; i++) { switch (makers[i].trim()) { // 메이저 Maker case '任天堂': koreanMakers.push('닌텐도'); break; case 'スクウェア・エニックス': koreanMakers.push('스퀘어 에닉스'); break; case 'コーエーテクモゲームス': koreanMakers.push('코에이 테크모 게임스'); break; case 'ポケモン': koreanMakers.push('포켓몬'); break; case 'バンダイナムコエンターテインメント': koreanMakers.push('반다이 남코 엔터테인먼트'); break; case 'アトラス': koreanMakers.push('아틀러스'); break; case 'セガ': koreanMakers.push('세가'); break; // 소규모 Maker case '日本一ソフトウェア': koreanMakers.push('니폰이치 소프트웨어'); break; case 'エンターグラム': koreanMakers.push('Entergram'); break; case 'フライハイワークス': koreanMakers.push('Flyhigh Works'); break; case 'フリュー': koreanMakers.push('후류'); break; case 'ポノス': koreanMakers.push('포노스'); break; case 'マーベラス': koreanMakers.push('마블러스 엔터테인먼트'); break; case 'スパイク・チュンソフト': koreanMakers.push('스파이크 춘 소프트'); break; case 'ドラガミゲームス': koreanMakers.push('DRAGAMI GAMES'); break; case 'アイディアファクトリー': koreanMakers.push('Idea Factory'); break; case 'アークシステムワークス': koreanMakers.push('아크 시스템 웍스'); break; case 'ユービーアイソフト': koreanMakers.push('유비소프트'); break; case 'レイアーク': koreanMakers.push('레이아크'); break; case 'ワンオアエイト': koreanMakers.push('One or Eight'); break; case 'インティ・クリエイツ': koreanMakers.push('인티 크리에이츠'); break; case 'クラウディッドレパードエンタテインメント': koreanMakers.push('Clouded Leopard Entertainment'); break; case 'カプコン': koreanMakers.push('캡콤'); break; case 'プロトタイプ': koreanMakers.push('PROTOTYPE Ltd'); break; case 'ディースリー・パブリッシャー': koreanMakers.push('D3 퍼블리셔'); break; case 'タイトー': koreanMakers.push('타이토'); break; case 'シーエフケー': koreanMakers.push('CFK'); break; case 'アクワイア': koreanMakers.push('어콰이어'); break; case '日本ファルコム': koreanMakers.push('일본 팔콤'); break; // 거르면 되는 Maker case 'ヒューネックス': koreanMakers.push('휴넥스'); break; case 'アニプレックス': koreanMakers.push('애니플렉스'); break; case 'ジー・モード': koreanMakers.push('G-Mode'); break; case 'イザナギゲームズ': koreanMakers.push('IzanagiGames'); break; case 'ラセングル': koreanMakers.push('Lasengle'); break; case 'ケムコ': koreanMakers.push('켐코'); break; case 'ネットマーブルコーポレーション': koreanMakers.push('넷마블'); break; case '工画堂スタジオ': koreanMakers.push('코가도 스튜디오'); break; case '賈船': koreanMakers.push('COSEN'); break; case 'ジェムドロップ': koreanMakers.push('잼드롭'); break; case 'アレス': koreanMakers.push('아레스'); break; case '日本コロムビア': koreanMakers.push('일본콜롬비아'); break; case 'クリプトン・フューチャー・メディア': koreanMakers.push('크립톤 퓨처 미디어'); break; case 'イマジニア': koreanMakers.push('이매지니아'); break; default: koreanMakers.push(makers[i]); break; } } return koreanMakers.join(', '); } // 태그 변환 함수 function convertTags(tags) { if (!tags) return ''; if (filterState.language !== 'ko') return tags; const tagList = tags.split(','); const koreanTags = []; for (let i = 0; i < tagList.length; i++) { switch (tagList[i].trim()) { case 'パーティー': koreanTags.push('파티'); break; case 'シューティング': koreanTags.push('슈팅'); break; case '格闘': koreanTags.push('격투'); break; case 'パズル': koreanTags.push('퍼즐'); break; case 'レース': koreanTags.push('레이스'); break; case 'ロールプレイング': koreanTags.push('롤플레잉'); break; case 'アクション': koreanTags.push('액션'); break; case 'ストラテジー': koreanTags.push('전략'); break; case 'ドット絵': koreanTags.push('도트 그림'); break; case 'サバイバル': koreanTags.push('서바이벌'); break; case 'リズムに合わせて': koreanTags.push('리듬에 맞춰'); break; case 'カードゲーム': koreanTags.push('카드 게임'); break; case '囲碁・将棋': koreanTags.push('바둑・쇼기'); break; case 'ボードゲーム': koreanTags.push('보드 게임'); break; case 'サッカー': koreanTags.push('축구'); break; case 'テーブルゲーム': koreanTags.push('테이블 게임'); break; case 'トランプ': koreanTags.push('트럼프'); break; case '麻雀': koreanTags.push('마작'); break; case 'トレーニング': koreanTags.push('트레이닝'); break; case '視点切りかえ': koreanTags.push('관점의 전환'); break; case 'あそびが盛りだくさん': koreanTags.push('다양한 즐길거리'); break; case '新しいエリアを切りひらく': koreanTags.push('새로운 지역을 개척한다'); break; case 'あそぶたびにマップが新しい': koreanTags.push('즐길때마다 새로운 맵'); break; case '大人数でバトル': koreanTags.push('많은 인원과 배틀'); break; case '最速タイムにチャレンジ': koreanTags.push('가장 빠른 시간에 도전'); break; case 'シミュレーション': koreanTags.push('시뮬레이션'); break; case 'スポーツ': koreanTags.push('스포츠'); break; case 'バレーボール': koreanTags.push('배구'); break; case 'ゴルフ': koreanTags.push('골프'); break; case 'バスケットボール': koreanTags.push('농구'); break; case 'テニス': koreanTags.push('테니스'); break; case '野球': koreanTags.push('야구'); break; case 'ボクシング': koreanTags.push('복싱'); break; case '経営シミュレーション': koreanTags.push('경영 시뮬레이션'); break; case 'コミュニケーション': koreanTags.push('커뮤니케이션'); break; case '音楽ゲーム': koreanTags.push('음악 게임'); break; case '学習・教育': koreanTags.push('학습・교육'); break; case 'ツール': koreanTags.push('도구'); break; case 'アドベンチャー': koreanTags.push('모험'); break; case '失敗したら最初から': koreanTags.push('실패하면 처음부터'); break; case 'なぞ解き': koreanTags.push('수수께끼'); break; case 'せまる敵から守りぬく': koreanTags.push('다가오는 적으로부터 지킨다'); break; case 'すばやい判断がきめ手': koreanTags.push('재빠른 판단이 관건'); break; case 'つくれる・あそべる': koreanTags.push('만들고 즐긴다'); break; case 'テキストアドベンチャー': koreanTags.push('텍스트 어드벤처'); break; case '恋愛': koreanTags.push('연애'); break; case '最高スコアにチャレンジ': koreanTags.push('최고 점수에 도전'); break; case '世界を自由にかけ回る': koreanTags.push('세계를 자유롭게 돌아다니다'); break; case '落下に注意': koreanTags.push('낙하주의'); break; case '目的はあなた次第': koreanTags.push('목적은 당신이 선택'); break; case '戦うたびに強くなる': koreanTags.push('싸울수록 성장'); break; case '手足や体と連動して操作': koreanTags.push('몸과 연동하여 조작'); break; case 'オンラインで対戦': koreanTags.push('온라인 대전'); break; case 'オンラインで協力': koreanTags.push('온라인 협력'); break; case 'キャラクターカスタマイズ': koreanTags.push('캐릭터 커스터마이즈'); break; case '3人称視点': koreanTags.push('3인칭 시점'); break; case 'Toy-Conが使える': koreanTags.push('Toy-Con을 사용할 수 있다'); break; case '難易度が選べる': koreanTags.push('난이도 선택 가능'); break; case 'キャラクターボイス': koreanTags.push('케릭터 음성'); break; case 'オンラインでフレンドと': koreanTags.push('친구와 온라인으로'); break; case '1台の本体でいっしょにあそべる': koreanTags.push('한 대의 본체에서 함께 놀 수 있다'); break; case 'ともだちや家族と集まって': koreanTags.push('친구와 가족과 함께'); break; case 'オンラインランキング': koreanTags.push('온라인 랭킹'); break; case '本体を持ちよってあそべる': koreanTags.push('게임기를 들고 플레이'); break; case 'クロスプラットフォームプレイ対応': koreanTags.push('크로스 플랫폼 플레이 대응'); break; default: koreanTags.push(tagList[i]); break; } } return koreanTags.join(', '); } // 출시일 변환 함수 function convertReleaseDate(releaseDate) { if (!releaseDate) return ''; if (filterState.language !== 'ko') return releaseDate; const date = new Date(releaseDate.replace(/年|月/g, '/').replace('日', '')); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); return `${year}년 ${month}월 ${day}일`; } // 국가 변환 함수 function convertCountry(country) { if (!country) return ''; switch (country) { case 'JPN': return filterState.language === 'ko' ? '일본판' : '日本版'; case 'KOR': return filterState.language === 'ko' ? '한국판' : '韓国版'; default: return country; } } function formatGameData(game) { return { ...game, formattedTitle: filterState.language === 'ko' ? game.koTitle || game.title : game.title, formattedReleaseDate: convertReleaseDate(game.release), formattedMaker: convertMaker(game.maker), formattedLanguage: convertLanguage(game.language), formattedTags: convertTags(game.tags), formattedCountry: convertCountry(game.country), }; } function getStatusClass(status) { switch (status) { case 'package': return 'bg-green-100 text-green-800'; case 'download': return 'bg-yellow-100 text-yellow-800'; case 'expansion': return 'bg-blue-100 text-blue-800'; default: return ''; } } function getCountryClass(country) { return country === 'JPN' ? 'text-red-600 hover:text-red-900' : 'text-indigo-600 hover:text-indigo-900'; } function createGameRow(game, index) { const tr = document.createElement('tr'); tr.className = `cursor-pointer hover:bg-indigo-50 ${index % 2 === 0 ? '' : 'bg-gray-50'}`; // 클릭 시 nsw-detail.html로 이동 (no 쿼리 포함) tr.addEventListener('click', () => { window.location.href = `nsw-detail.html?no=${encodeURIComponent(game.no)}`; }); tr.innerHTML = `
${game.no}. ${game.formattedTitle}
${game.formattedReleaseDate}
${game.formattedMaker}
${game.formattedLanguage}
${game.status}
${game.formattedTags}
${game.formattedCountry}
`; return tr; } // 필터 초기화 함수 function resetFilters() { // 모든 체크박스 해제 document.querySelectorAll('input[type="checkbox"]').forEach(checkbox => { checkbox.checked = false; }); // 필터 상태 초기화 filterState.filters = { language: [], status: [], country: [], cero: [], }; // 게임 목록 다시 렌더링 renderGames(); } // 필터 초기화 버튼 이벤트 리스너 설정 document.getElementById('resetFilters').addEventListener('click', resetFilters); // 필터 체크박스 이벤트 리스너 설정 function setupFilterListeners() { // 언어 필터 document.querySelectorAll('input[name="language-filter"]').forEach(checkbox => { checkbox.addEventListener('change', () => { updateFilters('language'); renderGames(); }); }); // 상태 필터 document.querySelectorAll('input[name="status-filter"]').forEach(checkbox => { checkbox.addEventListener('change', () => { updateFilters('status'); renderGames(); }); }); // 국가 필터 document.querySelectorAll('input[name="country-filter"]').forEach(checkbox => { checkbox.addEventListener('change', () => { updateFilters('country'); renderGames(); }); }); // CERO 필터 document.querySelectorAll('input[name="cero-filter"]').forEach(checkbox => { checkbox.addEventListener('change', () => { updateFilters('cero'); renderGames(); }); }); } // 필터 상태 업데이트 function updateFilters(type) { const checkboxes = document.querySelectorAll(`input[name="${type}-filter"]:checked`); filterState.filters[type] = Array.from(checkboxes).map(checkbox => checkbox.value); } // 필터링 함수 function filterGames(games) { return games.filter(game => { // 언어 필터 if (filterState.filters.language.length > 0) { const hasKorean = game.language.includes('韓国語'); const hasKoreanFilter = filterState.filters.language.includes('koreanSupport'); const hasNotSupportedFilter = filterState.filters.language.includes('koreanNotSupport'); // 한국어 지원과 미지원이 모두 체크된 경우 모든 게임 표시 if (hasKoreanFilter && hasNotSupportedFilter) { return true; } // 한국어 지원만 체크된 경우 한국어 지원 게임만 표시 if (hasKoreanFilter && !hasNotSupportedFilter) { return hasKorean; } // 한국어 미지원만 체크된 경우 한국어 미지원 게임만 표시 if (!hasKoreanFilter && hasNotSupportedFilter) { return !hasKorean; } // 아무것도 체크되지 않은 경우 필터링하지 않음 return true; } // 상태 필터 if (filterState.filters.status.length > 0) { const hasExtensionFilter = filterState.filters.status.includes('extension'); const hasOtherStatusFilters = filterState.filters.status.filter(status => status !== 'extension').length > 0; // extension 필터가 체크된 경우 if (hasExtensionFilter) { // extension 값이 null이 아닌 게임만 표시 if (game.extension === null) return false; } // 다른 상태 필터가 체크된 경우 if (hasOtherStatusFilters) { const otherStatuses = filterState.filters.status.filter(status => status !== 'extension'); if (!otherStatuses.includes(game.status)) return false; } } // 국가 필터 if ( filterState.filters.country.length > 0 && !filterState.filters.country.includes(game.country) ) { return false; } // CERO 필터 if (filterState.filters.cero.length > 0 && !filterState.filters.cero.includes(game.cero)) { return false; } return true; }); } // 정렬 함수 function sortGames(games) { switch (filterState.sortBy) { case 'sortByNoDesc': return [...games].sort((a, b) => b.no - a.no); case 'sortByNo': return [...games].sort((a, b) => a.no - b.no); case 'sortByDateDesc': return [...games].sort((a, b) => { const aDate = new Date(a.release.replace(/年|月/g, '/').replace(/日/g, '')).toUTCString(); const bDate = new Date(b.release.replace(/年|月/g, '/').replace(/日/g, '')).toUTCString(); const dateDiff = new Date(bDate) - new Date(aDate); return dateDiff === 0 ? b.no - a.no : dateDiff; }); case 'sortByDate': return [...games].sort((a, b) => { const aDate = new Date(a.release.replace(/年|月/g, '/').replace(/日/g, '')).toUTCString(); const bDate = new Date(b.release.replace(/年|月/g, '/').replace(/日/g, '')).toUTCString(); const dateDiff = new Date(aDate) - new Date(bDate); return dateDiff === 0 ? b.no - a.no : dateDiff; }); case 'sortByPurchaseDateDesc': return [...games].sort((a, b) => { if (!a.purchaseInformation?.date || !b.purchaseInformation?.date) { return !a.purchaseInformation?.date ? 1 : -1; } const aDate = new Date(a.purchaseInformation.date.replace(/\./g, '/')).toUTCString(); const bDate = new Date(b.purchaseInformation.date.replace(/\./g, '/')).toUTCString(); const dateDiff = new Date(bDate) - new Date(aDate); return dateDiff === 0 ? b.no - a.no : dateDiff; }); case 'sortByPurchaseDate': return [...games].sort((a, b) => { if (!a.purchaseInformation?.date || !b.purchaseInformation?.date) { return !a.purchaseInformation?.date ? 1 : -1; } const aDate = new Date(a.purchaseInformation.date.replace(/\./g, '/')).toUTCString(); const bDate = new Date(b.purchaseInformation.date.replace(/\./g, '/')).toUTCString(); const dateDiff = new Date(aDate) - new Date(bDate); return dateDiff === 0 ? b.no - a.no : dateDiff; }); case 'sortByRandom': return [...games].sort(() => Math.random() - 0.5); default: return games; } } // 정렬 UI 초기화 function setupSortUI() { const sortButton = document.getElementById('sort-button'); const sortOptions = document.getElementById('sort-options'); const sortLabel = document.getElementById('sort-label'); // 정렬 버튼 클릭 이벤트 sortButton.addEventListener('click', () => { sortOptions.classList.toggle('hidden'); const isExpanded = sortOptions.classList.contains('hidden') ? 'false' : 'true'; sortButton.setAttribute('aria-expanded', isExpanded); }); // 정렬 옵션 클릭 이벤트 sortOptions.querySelectorAll('li').forEach(option => { option.addEventListener('click', () => { const value = option.getAttribute('data-value'); const name = uiTexts[filterState.language].sortOptions[value]; // 선택된 옵션 업데이트 sortOptions.querySelectorAll('li').forEach(li => { li.querySelector('span').classList.remove('font-semibold'); li.querySelector('svg')?.parentElement?.classList.add('hidden'); }); option.querySelector('span').classList.add('font-semibold'); const checkIcon = option.querySelector('svg')?.parentElement; if (checkIcon) checkIcon.classList.remove('hidden'); // 정렬 상태 업데이트 filterState.sortBy = value; sortButton.querySelector('span').textContent = name; sortOptions.classList.add('hidden'); sortButton.setAttribute('aria-expanded', 'false'); // 게임 목록 다시 렌더링 renderGames(); }); }); // 외부 클릭 시 드롭다운 닫기 document.addEventListener('click', e => { if (!sortButton.contains(e.target) && !sortOptions.contains(e.target)) { sortOptions.classList.add('hidden'); sortButton.setAttribute('aria-expanded', 'false'); } }); // 정렬 옵션 텍스트 업데이트 function updateSortOptionsText() { const texts = uiTexts[filterState.language].sortOptions; sortLabel.textContent = filterState.language === 'ko' ? '정렬' : '並び替え'; sortButton.querySelector('span').textContent = texts[filterState.sortBy]; sortOptions.querySelectorAll('li').forEach(option => { const value = option.getAttribute('data-value'); option.querySelector('span').textContent = texts[value]; }); } // 언어 변경 시 정렬 옵션 텍스트 업데이트 languageRadios.forEach(radio => { radio.addEventListener('change', e => { filterState.language = e.target.value; updateSortOptionsText(); }); }); // 초기 정렬 옵션 텍스트 설정 updateSortOptionsText(); } // 게임 렌더링 함수 수정 function renderGames() { loading.classList.remove('hidden'); // 데이터 포맷팅 const formattedGames = NSW_DB.map(formatGameData); // 필터링 적용 const filteredGames = filterGames(formattedGames); // 정렬 적용 const sortedGames = sortGames(filteredGames); // 게임 개수 업데이트 gameCount.textContent = `${sortedGames.length} ${uiTexts[filterState.language].count}`; // 테이블 내용 업데이트 gameList.innerHTML = ''; sortedGames.forEach((game, index) => { gameList.appendChild(createGameRow(game, index)); }); loading.classList.add('hidden'); } // 초기화 setupFilterListeners(); setupSortUI(); updateUITexts(); renderGames(); });