diff --git a/data.js b/data.js index 8a36a53..fbe8182 100644 --- a/data.js +++ b/data.js @@ -1,6 +1,6 @@ const products = [ { - id: 1, + id: 'i3zgj4zl', title: '플로럴 플로우러브', price: 60000, currency: '₩', @@ -23,7 +23,7 @@ const products = [ '', '', ], - images: ['/images/games/20260204_002254.jpg'], + images: ['/images/games/i3zgj4zl_01.jpg','/images/games/i3zgj4zl_02.jpg','/images/games/i3zgj4zl_03.jpg','/images/games/i3zgj4zl_04.jpg'], customTag: '완전생산한정판', specs: { purchaseDate: '', diff --git a/images/games/20260204_002254.jpg b/images/games/i3zgj4zl_01.jpg similarity index 100% rename from images/games/20260204_002254.jpg rename to images/games/i3zgj4zl_01.jpg diff --git a/images/games/i3zgj4zl_02.jpg b/images/games/i3zgj4zl_02.jpg new file mode 100644 index 0000000..9a2597f Binary files /dev/null and b/images/games/i3zgj4zl_02.jpg differ diff --git a/images/games/i3zgj4zl_03.jpg b/images/games/i3zgj4zl_03.jpg new file mode 100644 index 0000000..50ad608 Binary files /dev/null and b/images/games/i3zgj4zl_03.jpg differ diff --git a/images/games/i3zgj4zl_04.jpg b/images/games/i3zgj4zl_04.jpg new file mode 100644 index 0000000..1a361f1 Binary files /dev/null and b/images/games/i3zgj4zl_04.jpg differ diff --git a/index.html b/index.html index b37e771..1793e94 100644 --- a/index.html +++ b/index.html @@ -215,8 +215,7 @@
- +
@@ -256,11 +255,11 @@
- -

입금 확인 후, 24시간 이내 발송

+

링크를 복사해 문의 시 전달해주세요.

diff --git a/scripts/app.js b/scripts/app.js index de543ca..03e4cba 100644 --- a/scripts/app.js +++ b/scripts/app.js @@ -81,6 +81,26 @@ let activeStatuses = new Set( .map(([status]) => status), ); + +// openModal 함수 내부에 추가하거나 전역으로 설정 +const copyBtn = document.getElementById('copy-link-btn'); +const copyBtnText = document.getElementById('copy-btn-text'); + +copyBtn.onclick = () => { + // 현재 도메인 + 제품 ID 쿼리 조합 + const shareUrl = `${window.location.origin}${window.location.pathname}?id=${product.id}`; + + navigator.clipboard.writeText(shareUrl).then(() => { + copyBtnText.textContent = "링크가 복사되었습니다!"; + copyBtn.classList.replace('bg-slate-900', 'bg-green-600'); + + setTimeout(() => { + copyBtnText.textContent = "상품 링크 복사하기"; + copyBtn.classList.replace('bg-green-600', 'bg-slate-900'); + }, 2000); + }); +}; + function getStatusChipClass(status, isActive) { const base = STATUS_COLOR[status] ?? ''; @@ -200,7 +220,7 @@ export function renderProducts(page) { pagedProducts.forEach((product) => { const isSold = STATUS_META[product.status]?.soldOut === true; const cardHtml = ` -
+
@@ -235,172 +255,107 @@ window.openModal = (id) => { const modal = document.getElementById('product-modal'); const images = product.images; - // 무한 루프를 위해 처음과 끝에 클론 추가 [마지막 이미지, ...원본 이미지..., 첫 이미지] + // --- 1. 이미지 및 UI 초기화 로직 --- const loopImages = [images[images.length - 1], ...images, images[0]]; - const mainImagesHtml = loopImages - .map( - (img) => ` -
- -
- `, - ) - .join(''); + .map(img => ` +
+ +
+ `).join(''); - // 2. 사이드 썸네일 동적 생성 const thumbnailsHtml = product.images - .map( - (img, idx) => ` - - `, - ) - .join(''); + .map((img, idx) => ` + + `).join(''); - // 3. 페이지네이션 도트 동적 생성 const dotsHtml = product.images - .map( - (_, idx) => ` - - `, - ) - .join(''); + .map((_, idx) => ` + + `).join(''); - const customTagElement = document.getElementById('modal-custom-tag'); - const tagText = product.customTag; - - if (tagText && tagText.trim() !== '') { - customTagElement.textContent = tagText; - customTagElement.classList.remove('hidden'); - - // 키워드별 색상 스타일 정의 - const tagStyles = { - 완전생산한정판: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400', - 특전포함: 'bg-pink-100 text-pink-700 dark:bg-pink-900/30 dark:text-pink-400', - 미개봉: 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400', - 무료배송: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', - }; - - // 기본 스타일 (정의되지 않은 텍스트일 경우) - const defaultStyle = 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-400'; - - // 기존 스타일 클래스 초기화 후 적용 - customTagElement.className = `px-2.5 py-1 rounded-lg text-xs font-bold uppercase tracking-wider ${tagStyles[tagText] || defaultStyle}`; - } else { - customTagElement.classList.add('hidden'); - } + // --- 2. 데이터 주입 --- + document.getElementById('modal-main-carousel').innerHTML = mainImagesHtml; + document.getElementById('modal-thumbnails').innerHTML = thumbnailsHtml; + document.getElementById('modal-dots').innerHTML = dotsHtml; + document.getElementById('modal-title').textContent = product.title; + document.getElementById('modal-price').textContent = `${product.currency}${product.price.toLocaleString()}`; + // 카테고리 및 상태 const modalCategory = document.getElementById('modal-category'); - if (modalCategory) { - modalCategory.textContent = product.category; - } + if (modalCategory) modalCategory.textContent = product.category; - // 2. 상태값 업데이트 (상태에 따른 디자인 변경 포함) const modalStatus = document.getElementById('modal-status'); if (modalStatus) { modalStatus.textContent = product.status; - - // 상태별 스타일 정의 (배경색, 글자색) const statusStyles = { 판매중: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400', 판매예정: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400', 판매완료: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400', 미판매: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400', }; - - // 기존 클래스 제거 후 해당 상태의 스타일 추가 modalStatus.className = 'px-2.5 py-1 rounded-lg text-xs font-bold uppercase tracking-wider ' + (statusStyles[product.status] || statusStyles['미판매']); } - // HTML 주입 - document.getElementById('modal-main-carousel').innerHTML = mainImagesHtml; - document.getElementById('modal-thumbnails').innerHTML = thumbnailsHtml; - document.getElementById('modal-dots').innerHTML = dotsHtml; - - // 1. 제품 상태 (specs.condition) 업데이트 - const conditionText = product.specs?.condition; - const isVerified = product.specs?.isVerified; - - const conditionRow = document.getElementById('modal-condition-row'); - const conditionValue = document.getElementById('modal-condition'); - const verifiedIcon = document.getElementById('modal-verified-icon'); - - // 1. 그레이드(condition) 값이 있는지 체크하여 라인 노출 결정 - if (conditionText && conditionText.trim() !== '') { - conditionValue.textContent = conditionText; - conditionRow.classList.remove('hidden'); - conditionRow.classList.add('flex'); - - // 2. 인증 여부에 따라 SVG 아이콘 노출 결정 - if (isVerified) { - verifiedIcon.classList.remove('hidden'); - } else { - verifiedIcon.classList.add('hidden'); - } + // 커스텀 태그 + const customTagElement = document.getElementById('modal-custom-tag'); + if (product.customTag?.trim()) { + customTagElement.textContent = product.customTag; + customTagElement.classList.remove('hidden'); } else { - // 값이 없으면 라인 전체 숨김 - conditionRow.classList.add('hidden'); - conditionRow.classList.remove('flex'); + customTagElement.classList.add('hidden'); } - // 2. 제품 설명 (fullDescription) 업데이트 + // 상세 설명 const modalDesc = document.getElementById('modal-desc'); if (modalDesc) { - const descData = product.fullDescription; - - if (Array.isArray(descData)) { - // 배열을
태그로 합쳐서 HTML로 주입 - modalDesc.innerHTML = descData.join('
'); - } else { - modalDesc.textContent = descData || ''; - } + modalDesc.innerHTML = Array.isArray(product.fullDescription) ? product.fullDescription.join('
') : (product.fullDescription || ''); } - // 구매일자 처리 (경로 수정: product.specs?.purchaseDate) - const modalDate = document.getElementById('modal-date'); - const modalDateRow = document.getElementById('modal-date-row'); - - // specs 객체 안의 purchaseDate를 가져옴 - const pDate = product.specs?.purchaseDate; - - if (pDate && pDate.trim() !== '' && pDate !== 'null') { - modalDate.textContent = pDate; - modalDateRow.classList.remove('hidden'); - modalDateRow.classList.add('flex'); - } else { - modalDateRow.classList.add('hidden'); - modalDateRow.classList.remove('flex'); + // --- 3. [핵심] 링크 복사 버튼 이벤트 바인딩 --- + const copyBtn = document.getElementById('copy-link-btn'); + const copyBtnText = document.getElementById('copy-btn-text'); + if (copyBtn) { + copyBtn.onclick = () => { + const shareUrl = `${window.location.origin}${window.location.pathname}?id=${product.id}`; + navigator.clipboard.writeText(shareUrl).then(() => { + if (copyBtnText) copyBtnText.textContent = "링크가 복사되었습니다!"; + copyBtn.classList.add('!bg-green-600'); + setTimeout(() => { + if (copyBtnText) copyBtnText.textContent = "상품 링크 복사하기"; + copyBtn.classList.remove('!bg-green-600'); + }, 2000); + }); + }; } - // 텍스트 정보 주입 (ID들 맞춰주세요) - document.getElementById('modal-title').textContent = product.title; - document.getElementById('modal-price').textContent = `${product.currency}${product.price.toLocaleString()}`; - // ... 나머지 정보 주입 - + // --- 4. 모달 활성화 및 초기 위치 설정 --- modal.classList.remove('hidden'); document.body.style.overflow = 'hidden'; - // 드래그 기능 다시 연결 const container = document.getElementById('modal-main-carousel-container'); - const carousel = document.getElementById('modal-main-carousel'); - carousel.innerHTML = mainImagesHtml; - - modal.classList.remove('hidden'); - document.body.style.overflow = 'hidden'; - - // 초기 위치 설정 (클론된 마지막 이미지 다음인 '진짜 첫 번째' 이미지로 이동) - // const initialIndex = 1; container.style.scrollBehavior = 'auto'; container.scrollLeft = container.clientWidth; - // 드래그 및 무한 루프 감시 시작 + // 캐러셀 초기화 initBetterCarousel(container, images.length); }; +/** + * 모달 닫기 (URL 정리 기능 포함) + */ +window.closeModal = () => { + document.getElementById('product-modal').classList.add('hidden'); + document.body.style.overflow = 'auto'; + + const cleanUrl = window.location.origin + window.location.pathname; + window.history.replaceState(null, '', cleanUrl); +}; + function initBetterCarousel(container, originalLength) { let isDragging = false; let startX = 0; @@ -530,11 +485,6 @@ window.changePage = (page) => { window.scrollTo({ top: 0, behavior: 'smooth' }); }; -window.closeModal = () => { - document.getElementById('product-modal').classList.add('hidden'); - document.body.style.overflow = 'auto'; -}; - // 초기 실행 document.addEventListener('DOMContentLoaded', () => renderProducts(currentPage)); @@ -670,3 +620,31 @@ renderStatusChips(); // 🔥 최초 필터 적용 (이게 첫 렌더) applyFilters(); + +// 초기 실행 시 호출 +document.addEventListener('DOMContentLoaded', () => { + renderProducts(currentPage); + checkUrlAndOpenModal(); +}); + + +function checkUrlAndOpenModal() { + const params = new URLSearchParams(window.location.search); + const productId = params.get('id'); // URL에서 가져온 ID (문자열) + + if (productId) { + // 데이터의 id와 URL의 id를 모두 문자열로 변환하여 비교 + const product = products.find((p) => String(p.id) === productId); + + if (product) { + // DOM 렌더링 시간을 고려해 약간의 지연 후 모달 오픈 + setTimeout(() => openModal(product.id), 100); + } + } +} + + +// [최종 ID 생성기] 매번 완전히 새로운 8자리 난수 출력 +const newId = Math.random().toString(36).substring(2, 10); + +console.log(`%c[NEW ID for data.js]: ${newId}`, "color: #137fec; font-weight: bold; border: 1px solid #137fec; padding: 2px 5px; border-radius: 4px;"); \ No newline at end of file