Refine resale list badges
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
## 화면/라우팅
|
## 화면/라우팅
|
||||||
- 목록 화면: `index.html`
|
- 목록 화면: `index.html`
|
||||||
- 주요 기능: 검색, 필터(언어/판매상태/국가/CERO), 정렬, 게임 개수 표시, 가격 확인 별·제품 상태 표시
|
- 주요 기능: 검색, 필터(언어/판매상태/국가/CERO), 정렬, 게임 개수 표시, 판매 정보 배지 표시
|
||||||
- 데이터 소스: `db/nsw.resale.db.js` (`export default` → `items` 배열)
|
- 데이터 소스: `db/nsw.resale.db.js` (`export default` → `items` 배열)
|
||||||
- 스크립트: `script/nsw.js`
|
- 스크립트: `script/nsw.js`
|
||||||
- 상세 화면: `nsw-detail.html`
|
- 상세 화면: `nsw-detail.html`
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
- `tags` (string|null): 장르/특성 태그
|
- `tags` (string|null): 장르/특성 태그
|
||||||
- `extension` (string[]|null): 추가 콘텐츠 목록
|
- `extension` (string[]|null): 추가 콘텐츠 목록
|
||||||
- `status` (string): `available` | `sold` (판매 가능/판매완료)
|
- `status` (string): `available` | `sold` (판매 가능/판매완료)
|
||||||
- `itemCondition` (string|null): `SEALED`(미개봉) | `OPENED`(개봉) | `null`(미정)
|
- `itemCondition` (string|null): 판매자가 직접 작성하는 제품 상태. 예: `미개봉 새제품`, `초회 한정판`
|
||||||
- `country` (string): `KOR` | `JPN`
|
- `country` (string): `KOR` | `JPN`
|
||||||
- `cero` (string|null): CERO 등급
|
- `cero` (string|null): CERO 등급
|
||||||
- `sale` (object):
|
- `sale` (object):
|
||||||
|
|||||||
10
index.html
10
index.html
@@ -516,16 +516,6 @@
|
|||||||
class="hidden w-28 px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell">
|
class="hidden w-28 px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell">
|
||||||
Status
|
Status
|
||||||
</th>
|
</th>
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
class="hidden w-28 px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell">
|
|
||||||
제품 상태
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
class="hidden py-3.5 pl-3 pr-4 text-left text-sm font-semibold text-gray-900 sm:table-cell">
|
|
||||||
Location
|
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody
|
<tbody
|
||||||
|
|||||||
@@ -104,9 +104,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatItemCondition(itemCondition) {
|
function formatItemCondition(itemCondition) {
|
||||||
if (!itemCondition) {
|
if (!itemCondition || itemCondition === '-') return '';
|
||||||
return language === 'ko' ? '미정' : '未設定';
|
|
||||||
}
|
|
||||||
|
|
||||||
const labels = {
|
const labels = {
|
||||||
ko: {
|
ko: {
|
||||||
@@ -282,11 +280,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
document.getElementById('gameCountry').textContent =
|
document.getElementById('gameCountry').textContent =
|
||||||
language === 'ko'
|
language === 'ko'
|
||||||
? game.country === 'JPN'
|
? game.country === 'JPN'
|
||||||
? '일본판'
|
? '🇯🇵 일본판'
|
||||||
: '한국판'
|
: '🇰🇷 한국 정발판'
|
||||||
: game.country === 'JPN'
|
: game.country === 'JPN'
|
||||||
? '日本版'
|
? '🇯🇵 日本版'
|
||||||
: '韓国版';
|
: '🇰🇷 韓国版';
|
||||||
|
|
||||||
// 게임 정보 설정
|
// 게임 정보 설정
|
||||||
const gameInfo = document.getElementById('gameInfo');
|
const gameInfo = document.getElementById('gameInfo');
|
||||||
|
|||||||
118
script/nsw.js
118
script/nsw.js
@@ -30,9 +30,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
title: '제목',
|
title: '제목',
|
||||||
info: '판매가',
|
info: '판매가',
|
||||||
status: '판매 상태',
|
status: '판매 상태',
|
||||||
role: '가격 범위',
|
|
||||||
itemCondition: '제품 상태',
|
|
||||||
location: '지역',
|
|
||||||
},
|
},
|
||||||
sortOptions: {
|
sortOptions: {
|
||||||
sortByNoDesc: '순번 최신순',
|
sortByNoDesc: '순번 최신순',
|
||||||
@@ -63,9 +60,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
title: 'タイトル',
|
title: 'タイトル',
|
||||||
info: '販売価格',
|
info: '販売価格',
|
||||||
status: '販売状態',
|
status: '販売状態',
|
||||||
role: '価格帯',
|
|
||||||
itemCondition: '商品状態',
|
|
||||||
location: '地域',
|
|
||||||
},
|
},
|
||||||
sortOptions: {
|
sortOptions: {
|
||||||
sortByNoDesc: '番号降順',
|
sortByNoDesc: '番号降順',
|
||||||
@@ -115,12 +109,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
headers[0].textContent = texts.tableHeaders.title;
|
headers[0].textContent = texts.tableHeaders.title;
|
||||||
headers[1].textContent = texts.tableHeaders.info;
|
headers[1].textContent = texts.tableHeaders.info;
|
||||||
headers[2].textContent = texts.tableHeaders.status;
|
headers[2].textContent = texts.tableHeaders.status;
|
||||||
headers[3].textContent = SHOW_RECOMMENDED_PRICE_RANGE_BY_DEFAULT
|
|
||||||
? texts.tableHeaders.role
|
|
||||||
: texts.tableHeaders.itemCondition;
|
|
||||||
headers[4].textContent = texts.tableHeaders.location;
|
|
||||||
headers[3].classList.add('sm:table-cell');
|
|
||||||
headers[3].classList.remove('sm:hidden');
|
|
||||||
|
|
||||||
// 로딩 텍스트 업데이트
|
// 로딩 텍스트 업데이트
|
||||||
loading.textContent = texts.loading;
|
loading.textContent = texts.loading;
|
||||||
@@ -612,13 +600,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
formattedConfidenceDescription: formatConfidenceDescription(game.sale?.confidence),
|
formattedConfidenceDescription: formatConfidenceDescription(game.sale?.confidence),
|
||||||
formattedSaleStatus: formatSaleStatus(game.status),
|
formattedSaleStatus: formatSaleStatus(game.status),
|
||||||
formattedItemCondition: formatItemCondition(game.itemCondition),
|
formattedItemCondition: formatItemCondition(game.itemCondition),
|
||||||
|
formattedEdition: formatEdition(game.country),
|
||||||
|
formattedKoreanSupport: formatKoreanSupport(game.language),
|
||||||
|
hasItemCondition: Boolean(formatItemCondition(game.itemCondition)),
|
||||||
|
hasKoreanSupport: hasKoreanLanguage(game.language),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatItemCondition(itemCondition) {
|
function formatItemCondition(itemCondition) {
|
||||||
if (!itemCondition) {
|
if (!itemCondition || itemCondition === '-') return '';
|
||||||
return filterState.language === 'ko' ? '미정' : '未設定';
|
|
||||||
}
|
|
||||||
|
|
||||||
const labels = {
|
const labels = {
|
||||||
ko: {
|
ko: {
|
||||||
@@ -634,6 +624,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return labels[filterState.language][itemCondition] || itemCondition;
|
return labels[filterState.language][itemCondition] || itemCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatEdition(country) {
|
||||||
|
if (country === 'JPN') {
|
||||||
|
return filterState.language === 'ko' ? '🇯🇵 일본판' : '🇯🇵 日本版';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (country === 'KOR') {
|
||||||
|
return filterState.language === 'ko' ? '🇰🇷 한국 정발판' : '🇰🇷 韓国版';
|
||||||
|
}
|
||||||
|
|
||||||
|
return country || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasKoreanLanguage(language) {
|
||||||
|
return Boolean(language?.includes('韓国語') || language?.includes('한국어'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatKoreanSupport(language) {
|
||||||
|
const isSupported = hasKoreanLanguage(language);
|
||||||
|
|
||||||
|
if (filterState.language === 'ko') {
|
||||||
|
return isSupported ? '🇰🇷 한국어 지원' : '❌ 한국어 미지원';
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSupported ? '🇰🇷 韓国語対応' : '❌ 韓国語非対応';
|
||||||
|
}
|
||||||
|
|
||||||
function formatKRW(value) {
|
function formatKRW(value) {
|
||||||
if (typeof value !== 'number') return uiTexts[filterState.language].pricePending;
|
if (typeof value !== 'number') return uiTexts[filterState.language].pricePending;
|
||||||
return `${value.toLocaleString('ko-KR')}원`;
|
return `${value.toLocaleString('ko-KR')}원`;
|
||||||
@@ -707,20 +723,41 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getItemConditionClass(itemCondition) {
|
function getItemConditionClass(itemCondition) {
|
||||||
switch (itemCondition) {
|
return 'bg-amber-100 text-amber-800';
|
||||||
case 'SEALED':
|
|
||||||
return 'bg-amber-100 text-amber-800';
|
|
||||||
case 'OPENED':
|
|
||||||
return 'bg-slate-100 text-slate-700';
|
|
||||||
default:
|
|
||||||
return 'bg-gray-100 text-gray-500';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCountryClass(country) {
|
function getEditionClass(country) {
|
||||||
return country === 'JPN'
|
return country === 'JPN' ? 'bg-red-100 text-red-800' : 'bg-indigo-100 text-indigo-800';
|
||||||
? 'text-red-600 hover:text-red-900'
|
}
|
||||||
: 'text-indigo-600 hover:text-indigo-900';
|
|
||||||
|
function getKoreanSupportClass(hasKoreanSupport) {
|
||||||
|
return hasKoreanSupport ? 'bg-emerald-100 text-emerald-800' : 'bg-gray-100 text-gray-600';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderInfoBadges(game, justifyClass = '') {
|
||||||
|
return `
|
||||||
|
<div class="flex flex-wrap items-center gap-1.5 ${justifyClass}">
|
||||||
|
${
|
||||||
|
game.hasItemCondition
|
||||||
|
? `<span class="rounded-full px-2 text-xs font-semibold leading-5 ${getItemConditionClass(
|
||||||
|
game.itemCondition,
|
||||||
|
)}">
|
||||||
|
${game.formattedItemCondition}
|
||||||
|
</span>`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
<span class="rounded-full px-2 text-xs font-semibold leading-5 ${getEditionClass(
|
||||||
|
game.country,
|
||||||
|
)}">
|
||||||
|
${game.formattedEdition}
|
||||||
|
</span>
|
||||||
|
<span class="rounded-full px-2 text-xs font-semibold leading-5 ${getKoreanSupportClass(
|
||||||
|
game.hasKoreanSupport,
|
||||||
|
)}">
|
||||||
|
${game.formattedKoreanSupport}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGameRow(game, index) {
|
function createGameRow(game, index) {
|
||||||
@@ -742,6 +779,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<div class="font-medium leading-5 text-gray-900 flex items-center gap-1">
|
<div class="font-medium leading-5 text-gray-900 flex items-center gap-1">
|
||||||
${game.sale?.priceVerified ? `${VERIFIED_PRICE_MARK} ` : ''}<span>${game.no}. ${game.formattedTitle}</span>
|
${game.sale?.priceVerified ? `${VERIFIED_PRICE_MARK} ` : ''}<span>${game.no}. ${game.formattedTitle}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
${renderInfoBadges(game)}
|
||||||
|
</div>
|
||||||
<div class="mt-1 max-w-lg text-xs leading-5 text-gray-500">
|
<div class="mt-1 max-w-lg text-xs leading-5 text-gray-500">
|
||||||
${game.formattedConfidenceDescription}
|
${game.formattedConfidenceDescription}
|
||||||
</div>
|
</div>
|
||||||
@@ -755,11 +795,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
)}">
|
)}">
|
||||||
${game.formattedSaleStatus}
|
${game.formattedSaleStatus}
|
||||||
</span>
|
</span>
|
||||||
<span class="rounded-full px-2 text-xs font-semibold leading-5 ${getItemConditionClass(
|
|
||||||
game.itemCondition,
|
|
||||||
)}">
|
|
||||||
${game.formattedItemCondition}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs leading-5 text-gray-500">
|
<div class="text-xs leading-5 text-gray-500">
|
||||||
${game.formattedPricingBasis}
|
${game.formattedPricingBasis}
|
||||||
@@ -789,25 +824,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
${game.formattedSaleStatus}
|
${game.formattedSaleStatus}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
${
|
|
||||||
SHOW_RECOMMENDED_PRICE_RANGE_BY_DEFAULT
|
|
||||||
? `<td class="hidden w-56 px-3 py-4 text-sm text-gray-500 sm:table-cell">
|
|
||||||
<div class="whitespace-nowrap text-gray-900">${game.formattedPriceRange || '-'}</div>
|
|
||||||
<div class="mt-1 line-clamp-2 text-xs text-gray-400">${game.sale?.checkedAt || ''}</div>
|
|
||||||
</td>`
|
|
||||||
: `<td class="hidden w-28 px-3 py-4 text-sm text-gray-500 sm:table-cell">
|
|
||||||
<div class="flex justify-center whitespace-nowrap rounded-full px-2 text-xs font-semibold leading-5 ${getItemConditionClass(
|
|
||||||
game.itemCondition,
|
|
||||||
)}">
|
|
||||||
${game.formattedItemCondition}
|
|
||||||
</div>
|
|
||||||
</td>`
|
|
||||||
}
|
|
||||||
<td class="hidden py-4 pl-3 pr-4 text-right text-sm font-medium sm:table-cell">
|
|
||||||
<div class="${getCountryClass(game.country)}">
|
|
||||||
${game.formattedCountry}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return tr;
|
return tr;
|
||||||
|
|||||||
Reference in New Issue
Block a user