덱 목록 무한 스크롤과 WebP 썸네일 최적화 추가

- 내 덱·공개 덱 목록을 무한 스크롤로 전환(공용 페이저 모듈 추가)
- 즐겨찾기 토글 시 카드만 in-place 갱신해 스크롤 위치 유지
- 저장 시 420px WebP 썸네일 생성·전송, 목록은 썸네일 우선 사용
- 삭제·미참조 정리에서 원본 PNG와 썸네일 함께 처리

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-02 18:17:58 +09:00
parent 63aabf61c4
commit a90bdcbe13
15 changed files with 516 additions and 85 deletions

View File

@@ -353,13 +353,13 @@
}
function renderDeckPreview(d) {
if (!d.preview_url) {
if (!d.preview_url && !d.thumbnail_url) {
return '<div class="deck-card-preview"><div class="flex h-full items-center justify-center bg-white text-[0.6875rem] font-semibold text-slate-400">미리보기 없음</div></div>';
}
const src = UaDeckApi.resolveMediaUrl(d.preview_url);
const version = d.updatedAt ? `?v=${encodeURIComponent(d.updatedAt)}` : '';
const previewSrc = escapeHtml(src + version);
return `<div class="deck-card-preview deck-card-preview--holdable" data-hold-preview data-preview-src="${previewSrc}"><img src="${previewSrc}" alt="" loading="lazy" class="admin-deck-preview-img h-full w-full bg-white object-contain" draggable="false" onerror="this.parentElement.classList.remove('deck-card-preview--holdable'); this.parentElement.removeAttribute('data-hold-preview'); this.parentElement.removeAttribute('data-preview-src'); this.parentElement.innerHTML='<div class=\\'flex h-full items-center justify-center bg-white text-[0.6875rem] font-semibold text-slate-400\\'>미리보기 없음</div>'" /></div>`;
const thumbSrc = escapeHtml(UaDeckApi.resolveMediaUrl(d.thumbnail_url || d.preview_url) + version);
const fullSrc = escapeHtml(UaDeckApi.resolveMediaUrl(d.preview_url || d.thumbnail_url) + version);
return `<div class="deck-card-preview deck-card-preview--holdable" data-hold-preview data-preview-src="${fullSrc}"><img src="${thumbSrc}" alt="" loading="lazy" class="admin-deck-preview-img h-full w-full bg-white object-contain" draggable="false" onerror="this.parentElement.classList.remove('deck-card-preview--holdable'); this.parentElement.removeAttribute('data-hold-preview'); this.parentElement.removeAttribute('data-preview-src'); this.parentElement.innerHTML='<div class=\\'flex h-full items-center justify-center bg-white text-[0.6875rem] font-semibold text-slate-400\\'>미리보기 없음</div>'" /></div>`;
}
/**