프리티어 변경

필터링 AND OR 조건 추가
데이터 JSON 구조 변경
오류 수정
This commit is contained in:
2026-02-22 15:45:22 +09:00
parent 42b5c0f047
commit f569000ba5
8 changed files with 1174 additions and 904 deletions

View File

@@ -81,7 +81,7 @@ window.handleThumbnailLeave = function (id) {
window.toggleSelectItem = function (id) {
if (state.selectedIds.has(id)) state.selectedIds.delete(id);
else state.selectedIds.add(id);
saveSelection();
renderProducts(state.currentPage);
updateSummary();
@@ -128,7 +128,7 @@ function renderEmpty(grid, tableWrapper, paginationContainer) {
grid.classList.remove('grid');
grid.classList.add('hidden');
tableWrapper.classList.add('hidden');
const emptyMsg = `
<div class="col-span-full flex flex-col items-center justify-center py-20 w-full text-center">
<svg class="w-20 h-20 text-slate-300 dark:text-slate-700 mb-6" viewBox="0 -960 960 960" fill="currentColor">
@@ -137,7 +137,7 @@ function renderEmpty(grid, tableWrapper, paginationContainer) {
<h3 class="text-xl font-bold text-slate-900 dark:text-white mb-2">검색 결과가 없습니다</h3>
<p class="text-slate-500 dark:text-slate-400 text-sm">입력하신 검색어나 선택한 필터를 확인해 주세요.</p>
</div>`;
grid.innerHTML = emptyMsg;
grid.classList.remove('hidden');
if (paginationContainer) paginationContainer.innerHTML = '';
@@ -149,13 +149,17 @@ function renderEmpty(grid, tableWrapper, paginationContainer) {
/** 그리드 뷰 렌더링 */
function renderGridView(grid, tableWrapper, products) {
grid.classList.replace('hidden', 'grid');
// 1. 표시 모드 전환 (테이블 숨기고 그리드 표시)
tableWrapper.classList.add('hidden');
grid.classList.remove('hidden');
// 2. [핵심] 렌더링 시 그리드 클래스 복구 및 보장
grid.classList.add('grid');
const summaryBar = document.getElementById('selection-summary');
if (summaryBar) summaryBar.classList.add('hidden');
grid.innerHTML = products.map(product => createProductCardHTML(product)).join('');
grid.innerHTML = products.map((product) => createProductCardHTML(product)).join('');
setupLazyLoading();
}
@@ -186,10 +190,14 @@ function createProductCardHTML(product) {
<span class="px-2 py-1 text-[10px] uppercase tracking-wider font-bold rounded ${STATUS_COLOR[product.status]} backdrop-blur-md border">${product.status}</span>
</div>
${!isSold && product.images?.length > 1 ? `
${
!isSold && product.images?.length > 1
? `
<div id="indicator-${product.id}" class="absolute bottom-3 left-1/2 -translate-x-1/2 hidden md:flex gap-1.5 opacity-0 group-hover:opacity-100 transition-all duration-300 pointer-events-none z-10">
${product.images.map((_, i) => `<div class="w-1.5 h-1.5 rounded-full transition-all duration-300 shadow-sm ${i === 0 ? 'bg-white scale-125' : 'bg-white/40'}"></div>`).join('')}
</div>` : ''}
</div>`
: ''
}
</div>
<div class="flex flex-col gap-1.5">
@@ -211,9 +219,9 @@ function createProductCardHTML(product) {
function renderTableView(grid, tableWrapper, products) {
grid.classList.add('hidden');
tableWrapper.classList.remove('hidden');
const tableBody = document.getElementById('product-table-body');
tableBody.innerHTML = products.map(product => createTableRowHTML(product)).join('');
tableBody.innerHTML = products.map((product) => createTableRowHTML(product)).join('');
updateSummary();
}
@@ -222,7 +230,7 @@ function createTableRowHTML(product) {
const meta = STATUS_META[product.status];
const isSold = meta?.soldOut === true;
const isSelectable = meta?.selectable !== false;
const conditionConfig = PRODUCT_CONDITIONS[product.specs.condition];
const conditionConfig = PRODUCT_CONDITIONS[product.condition];
const conditionDisplay = conditionConfig ? conditionConfig.label : '상세 설명 참고 ';
const conditionClass = conditionConfig ? conditionConfig.color : 'text-slate-500';
@@ -253,35 +261,38 @@ function updateSelectAllCheckbox(page) {
if (!selectAllCheck) return;
const startIndex = (page - 1) * ITEMS_PER_PAGE;
const currentSelectableItems = state.visibleProducts
.slice(startIndex, startIndex + ITEMS_PER_PAGE)
.filter((p) => STATUS_META[p.status]?.selectable !== false);
const currentSelectableItems = state.visibleProducts.slice(startIndex, startIndex + ITEMS_PER_PAGE).filter((p) => STATUS_META[p.status]?.selectable !== false);
selectAllCheck.checked = currentSelectableItems.length > 0 &&
currentSelectableItems.every((p) => state.selectedIds.has(p.id));
selectAllCheck.checked = currentSelectableItems.length > 0 && currentSelectableItems.every((p) => state.selectedIds.has(p.id));
}
/** Intersection Observer를 이용한 썸네일 지연 로딩 */
function setupLazyLoading() {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const card = entry.target;
const productId = card.getAttribute('data-id');
const product = state.visibleProducts.find((p) => p.id === productId);
const thumb = document.getElementById(`thumb-${productId}`);
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const card = entry.target;
const productId = card.getAttribute('data-id');
const product = state.visibleProducts.find((p) => p.id === productId);
const thumb = document.getElementById(`thumb-${productId}`);
if (product && thumb) {
thumb.style.backgroundImage = `url("${product.images[0]}")`;
// 마우스 호버를 대비해 나머지 이미지 미리 로드
if (!STATUS_META[product.status]?.soldOut && product.images.length > 1) {
product.images.slice(1).forEach(url => { const img = new Image(); img.src = url; });
if (product && thumb) {
thumb.style.backgroundImage = `url("${product.images[0]}")`;
// 마우스 호버를 대비해 나머지 이미지 미리 로드
if (!STATUS_META[product.status]?.soldOut && product.images.length > 1) {
product.images.slice(1).forEach((url) => {
const img = new Image();
img.src = url;
});
}
}
observer.unobserve(card);
}
observer.unobserve(card);
}
});
}, { threshold: 0.1 });
});
},
{ threshold: 0.1 },
);
document.querySelectorAll('.product-card').forEach((card) => observer.observe(card));
}
@@ -314,4 +325,4 @@ export function changePage(page) {
state.currentPage = page;
renderProducts(page);
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}