feat(ui): 대시보드 떡상 리더보드 썸네일 클릭 미리보기

수집함처럼, 떡상 후보 리더보드의 썸네일을 클릭하면 YouTube 임베드(9:16)
미리보기 팝업이 바로 뜨도록 추가. 편집 정체성에 맞춘 모달(.fd-vmodal),
배경 클릭/ESC로 닫힘, 닫을 때 iframe 비워 재생 중지.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hehihoho3@gmail.com 2026-06-16 14:52:24 +09:00
parent b97e4644ea
commit c7ce8de90e

View File

@ -69,6 +69,17 @@
</section> </section>
</div> </div>
<!-- 영상 미리보기 모달 -->
<div id="videoModal" class="fd-vmodal" onclick="if(event.target===this) closeVideoModal()">
<div class="fd-vmodal-card">
<div class="fd-vmodal-head">
<span class="fd-vmodal-title" id="vmTitle">미리보기</span>
<button class="fd-vmodal-x" onclick="closeVideoModal()" aria-label="닫기">&times;</button>
</div>
<div id="vmFrame" class="fd-vmodal-frame"></div>
</div>
</div>
</div> </div>
<style> <style>
@ -155,6 +166,17 @@
.fd-row .v b{ color:var(--fd-ink); } .fd-row .v b{ color:var(--fd-ink); }
.fd-empty{ font-family:var(--fd-mono); font-size:11px; color:var(--fd-ink-3); padding:14px 0; } .fd-empty{ font-family:var(--fd-mono); font-size:11px; color:var(--fd-ink-3); padding:14px 0; }
/* 영상 미리보기 모달 */
.fd-vmodal{ display:none; position:fixed; inset:0; z-index:1000; background:rgba(10,10,12,.86); align-items:center; justify-content:center; padding:20px; }
.fd-vmodal.open{ display:flex; }
.fd-vmodal-card{ background:var(--fd-panel); border:1.5px solid var(--fd-rule-strong); box-shadow:0 20px 60px rgba(0,0,0,.4); }
.fd-vmodal-head{ display:flex; justify-content:space-between; align-items:center; gap:14px; padding:11px 14px; border-bottom:1.5px solid var(--fd-rule-strong); }
.fd-vmodal-title{ font-weight:600; font-size:13px; color:var(--fd-ink); max-width:300px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.fd-vmodal-x{ background:none; border:none; font-size:24px; line-height:1; cursor:pointer; color:var(--fd-ink-2); padding:0 2px; }
.fd-vmodal-x:hover{ color:var(--fd-ink); }
.fd-vmodal-frame{ width:min(360px,90vw); aspect-ratio:9/16; max-height:78vh; background:#000; }
.fd-vmodal-frame iframe{ width:100%; height:100%; border:0; display:block; }
@media (max-width:1100px){ .fd-cols{ grid-template-columns:1fr; } .fd-actions{ grid-template-columns:1fr; } .fd-act{ border-right:none; border-bottom:1.5px solid var(--fd-rule-strong); } } @media (max-width:1100px){ .fd-cols{ grid-template-columns:1fr; } .fd-actions{ grid-template-columns:1fr; } .fd-act{ border-right:none; border-bottom:1.5px solid var(--fd-rule-strong); } }
</style> </style>
@ -205,7 +227,8 @@
const ratio = v.viewsPerSubRatio!=null ? Number(v.viewsPerSubRatio).toFixed(0)+'×' : ''; const ratio = v.viewsPerSubRatio!=null ? Number(v.viewsPerSubRatio).toFixed(0)+'×' : '';
return `<div class="fd-lead" data-id="${v.id}"> return `<div class="fd-lead" data-id="${v.id}">
<div class="fd-rk">${i+1}</div> <div class="fd-rk">${i+1}</div>
<img class="fd-th" src="${esc(v.thumbnailUrl)}" alt=""> <img class="fd-th" src="${esc(v.thumbnailUrl)}" alt="" title="미리보기" style="cursor:pointer;"
data-vid="${v.videoId}" data-title="${esc(v.title)}" onclick="openVideoModal(this.dataset.vid, this.dataset.title)">
<div style="min-width:0;"> <div style="min-width:0;">
<div class="fd-t"><a href="https://www.youtube.com/watch?v=${v.videoId}" target="_blank">${esc(v.title)}</a></div> <div class="fd-t"><a href="https://www.youtube.com/watch?v=${v.videoId}" target="_blank">${esc(v.title)}</a></div>
<div class="fd-s">SHORTS · ${esc(v.channelTitle||'')} · ${fmt(v.viewCount)}</div> <div class="fd-s">SHORTS · ${esc(v.channelTitle||'')} · ${fmt(v.viewCount)}</div>
@ -260,6 +283,19 @@
} catch(e){ alert('제외 실패: '+e.message); } } catch(e){ alert('제외 실패: '+e.message); }
} }
// ----- 영상 미리보기 (수집함과 동일) -----
function openVideoModal(vid, title){
document.getElementById('vmTitle').textContent = title || '미리보기';
document.getElementById('vmFrame').innerHTML =
'<iframe src="https://www.youtube.com/embed/' + vid + '?autoplay=1" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
document.getElementById('videoModal').classList.add('open');
}
function closeVideoModal(){
document.getElementById('vmFrame').innerHTML = '';
document.getElementById('videoModal').classList.remove('open');
}
document.addEventListener('keydown', e => { if(e.key === 'Escape') closeVideoModal(); });
loadDashboard(); loadDashboard();
/*]]>*/ /*]]>*/
</script> </script>