diff --git a/data/games.js b/data/games.js index b30a3b9..2f35da2 100644 --- a/data/games.js +++ b/data/games.js @@ -1,4 +1,118 @@ const games = [ + { + id: 'r7c2v9km', + createdAt: '2026-02-18', + updatedAt: '2026-02-18', + + title: '한계돌파 모에로 크리스탈 H', + price: 75000, + currency: '₩', + category: 'Games', + status: '판매중', + customTag: '', + + tags: ['Switch', 'KR'], + + images: ['/images/games/r7c2v9km_01.jpg', '/images/games/r7c2v9km_02.jpg', '/images/games/r7c2v9km_03.jpg'], + + description: '개봉품, 한국 정발판, OPP 보관', + + specs: { + purchaseDate: '', + condition: 'EXCELLENT', + isVerified: true, + }, + + fullDescription: ['한계돌파 모에로 크리스탈 H (限界凸起 モエロクリスタル H) 닌텐도 스위치용 패키지입니다.', '한국 정식 발매판 제품입니다.', '', '개봉 후 OPP에 넣어 보관·관리했으며', '전체적으로 상태가 매우 좋은 편입니다.', '', '', ''], + }, + { + id: 'q8m3r5yk', + createdAt: '2026-02-18', + updatedAt: '2026-02-18', + + title: '페이퍼 마리오 종이접기 킹', + price: 40000, + currency: '₩', + category: 'Games', + status: '판매중', + customTag: '', + + tags: ['Switch', 'JP'], + + images: ['/images/games/q8m3r5yk_01.jpg', '/images/games/q8m3r5yk_02.jpg', '/images/games/q8m3r5yk_03.jpg'], + + description: '개봉품, 일본판, 한국어 지원, OPP 보관', + + specs: { + purchaseDate: '', + condition: 'EXCELLENT', + isVerified: true, + }, + + fullDescription: ['페이퍼 마리오 종이접기 킹 (ペーパーマリオオリガミキング) 닌텐도 스위치용 패키지입니다.', '일본판 제품이며 한국어를 지원합니다.', '', '개봉 후 OPP에 넣어 보관·관리했으며', '전체적으로 상태가 매우 좋은 편입니다.', '', '', ''], + }, + { + id: 'k7p2x9qa', + createdAt: '2026-02-18', + updatedAt: '2026-02-18', + + title: '슈퍼 마리오 3D 컬렉션', + price: 140000, + currency: '₩', + category: 'Games', + status: '판매중', + customTag: '', + + tags: ['Switch', 'JP'], + + images: ['/images/games/k7p2x9qa_01.jpg', '/images/games/k7p2x9qa_02.jpg', '/images/games/k7p2x9qa_03.jpg'], + + description: '미개봉 새제품, 일본판, 한국어 미지원', + + specs: { + purchaseDate: '', + condition: 'BRAND_NEW', + isVerified: true, + }, + + fullDescription: [ + '슈퍼 마리오 3D 컬렉션 (スーパーマリオ 3Dコレクション) 닌텐도 스위치용 패키지입니다.', + '일본판 미개봉 새제품입니다.', + '', + '수록 작품:', + '・『スーパーマリオ64』(1996년 / Nintendo 64)', + '・『スーパーマリオサンシャイン』(2002년 / 게임큐브)', + '・『スーパーマリオギャラクシー』(2007년 / Wii)', + '', + '지원 언어: 일본어, 영어, 프랑스어, 독일어', + ], + }, + { + id: 'k8d2m4qs', + createdAt: '2026-02-18', + updatedAt: '2026-02-18', + + title: '사무라이 메이든', + price: 40000, + currency: '₩', + category: 'Games', + status: '판매중', + customTag: '', + + tags: ['Switch', 'JP'], + + images: ['/images/games/k8d2m4qs_01.jpg', '/images/games/k8d2m4qs_02.jpg', '/images/games/k8d2m4qs_03.jpg'], + + description: '개봉 후 OPP 보관, 일본판(JP), 한국어 지원', + + specs: { + purchaseDate: '', + condition: 'EXCELLENT', + isVerified: true, + }, + + fullDescription: ['사무라이 메이든 (SAMURAI MAIDEN -サムライメイデン-) 닌텐도 스위치용 패키지입니다.', '일본판(JP) 버전이며 한국어를 지원합니다.', '개봉 후 OPP에 넣어 보관했으며 상태는 매우 좋습니다.', '', '', '', '', ''], + }, { id: 'm8q2v7kx', createdAt: '2026-02-16', diff --git a/images/games/k7p2x9qa_01.jpg b/images/games/k7p2x9qa_01.jpg new file mode 100644 index 0000000..b444acf Binary files /dev/null and b/images/games/k7p2x9qa_01.jpg differ diff --git a/images/games/k7p2x9qa_02.jpg b/images/games/k7p2x9qa_02.jpg new file mode 100644 index 0000000..90e6d9f Binary files /dev/null and b/images/games/k7p2x9qa_02.jpg differ diff --git a/images/games/k7p2x9qa_03.jpg b/images/games/k7p2x9qa_03.jpg new file mode 100644 index 0000000..544227d Binary files /dev/null and b/images/games/k7p2x9qa_03.jpg differ diff --git a/images/games/k8d2m4qs_01.jpg b/images/games/k8d2m4qs_01.jpg new file mode 100644 index 0000000..39bddc7 Binary files /dev/null and b/images/games/k8d2m4qs_01.jpg differ diff --git a/images/games/k8d2m4qs_02.jpg b/images/games/k8d2m4qs_02.jpg new file mode 100644 index 0000000..8e7f378 Binary files /dev/null and b/images/games/k8d2m4qs_02.jpg differ diff --git a/images/games/k8d2m4qs_03.jpg b/images/games/k8d2m4qs_03.jpg new file mode 100644 index 0000000..6c46fd8 Binary files /dev/null and b/images/games/k8d2m4qs_03.jpg differ diff --git a/images/games/q8m3r5yk_01.jpg b/images/games/q8m3r5yk_01.jpg new file mode 100644 index 0000000..e1850e7 Binary files /dev/null and b/images/games/q8m3r5yk_01.jpg differ diff --git a/images/games/q8m3r5yk_02.jpg b/images/games/q8m3r5yk_02.jpg new file mode 100644 index 0000000..4fe7ae1 Binary files /dev/null and b/images/games/q8m3r5yk_02.jpg differ diff --git a/images/games/q8m3r5yk_03.jpg b/images/games/q8m3r5yk_03.jpg new file mode 100644 index 0000000..872d15e Binary files /dev/null and b/images/games/q8m3r5yk_03.jpg differ diff --git a/images/games/r7c2v9km_01.jpg b/images/games/r7c2v9km_01.jpg new file mode 100644 index 0000000..d260a9d Binary files /dev/null and b/images/games/r7c2v9km_01.jpg differ diff --git a/images/games/r7c2v9km_02.jpg b/images/games/r7c2v9km_02.jpg new file mode 100644 index 0000000..4d651c4 Binary files /dev/null and b/images/games/r7c2v9km_02.jpg differ diff --git a/images/games/r7c2v9km_03.jpg b/images/games/r7c2v9km_03.jpg new file mode 100644 index 0000000..a8f936e Binary files /dev/null and b/images/games/r7c2v9km_03.jpg differ diff --git a/scripts/productList.js b/scripts/productList.js index b2cee8c..ebd9106 100644 --- a/scripts/productList.js +++ b/scripts/productList.js @@ -3,6 +3,90 @@ import { state, saveSelection } from './state.js'; import { ITEMS_PER_PAGE, STATUS_META, STATUS_COLOR, PRODUCT_CONDITIONS } from './config.js'; import { updateSummary } from './main.js'; +// --- 터치 및 드래그 관련 전역 변수 및 핸들러 --- +window.isDragging = false; +let touchStartX = 0; +let touchStartY = 0; + +// 터치 기기 여부 확인 +const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; + +window.handleTouchStart = function (e) { + window.isDragging = false; + touchStartX = e.touches[0].clientX; + touchStartY = e.touches[0].clientY; +}; + +window.handleTouchMove = function (e) { + const touchX = e.touches[0].clientX; + const touchY = e.touches[0].clientY; + + // 10px 이상 움직이면 드래그(스크롤)로 간주 + if (Math.abs(touchX - touchStartX) > 10 || Math.abs(touchY - touchStartY) > 10) { + window.isDragging = true; + } +}; + +window.handleTouchEnd = function (e) { + // 필요한 경우 추가 로직 작성 가능 (현재는 isDragging 상태 유지만으로 충분) +}; + +// 썸네일 호버 핸들러 (PC에서만 동작하도록 수정) +window.handleThumbnailHover = function (e, id) { + if (isTouchDevice) return; // 모바일에서는 호버 로직 실행 안 함 + + const product = state.visibleProducts.find((p) => p.id === id); + if (!product || !product.images || product.images.length <= 1) return; + + const rect = e.currentTarget.getBoundingClientRect(); + const x = e.clientX - rect.left; + const sectionWidth = rect.width / product.images.length; + const index = Math.floor(x / sectionWidth); + + const thumb = document.getElementById(`thumb-${id}`); + const indicators = document.querySelector(`#indicator-${id}`)?.children; + + if (thumb && product.images[index]) { + thumb.style.backgroundImage = `url("${product.images[index]}")`; + } + + if (indicators) { + Array.from(indicators).forEach((dot, i) => { + if (i === index) { + dot.classList.add('bg-white', 'scale-125'); + dot.classList.remove('bg-white/40'); + } else { + dot.classList.remove('bg-white', 'scale-125'); + dot.classList.add('bg-white/40'); + } + }); + } +}; + +window.handleThumbnailLeave = function (id) { + if (isTouchDevice) return; + + const product = state.visibleProducts.find((p) => p.id === id); + const thumb = document.getElementById(`thumb-${id}`); + const indicators = document.querySelector(`#indicator-${id}`)?.children; + + if (thumb && product) { + thumb.style.backgroundImage = `url("${product.images[0]}")`; + } + + if (indicators) { + Array.from(indicators).forEach((dot, i) => { + if (i === 0) { + dot.classList.add('bg-white', 'scale-125'); + dot.classList.remove('bg-white/40'); + } else { + dot.classList.remove('bg-white', 'scale-125'); + dot.classList.add('bg-white/40'); + } + }); + } +}; + // 1. 체크박스 전역 핸들러 등록 window.toggleSelectItem = function (id) { if (state.selectedIds.has(id)) { @@ -24,32 +108,24 @@ export function renderProducts(page = 1) { if (!grid || !tableWrapper) return; - // 1. 결과가 0개인 경우 안내 if (state.visibleProducts.length === 0) { grid.classList.remove('grid'); grid.classList.add('hidden'); tableWrapper.classList.add('hidden'); - - // 검색 결과 없음 메시지를 표시할 별도의 컨테이너가 없다면 grid 영역을 빌려 씁니다. const emptyMsg = `
${isNonSale ? 'Not for Sale' : `${product.currency || '₩'}${product.price.toLocaleString()}`}
-${product.description}
-+ ${isNonSale ? 'Not for Sale' : `${product.currency || '₩'}${product.price.toLocaleString()}`} +
+${product.description}