fix: [academy] 방화셔터 이미지 hover 시 화면 중앙 대형 프리뷰 효과 구현

- 이미지 hover 시 350ms 후 화면 중앙에 80vh 크기로 확대 프리뷰
- backdrop blur 오버레이 + scale 애니메이션 효과
- 프리뷰 클릭 시 기존 라이트박스로 전환
This commit is contained in:
김보곤
2026-02-22 20:54:11 +09:00
parent 4f66edae0f
commit 7abf39264e

View File

@@ -4,17 +4,66 @@
@push('styles')
<style>
/* 이미지 기본 스타일 */
.academy-img-hover {
transition: transform 0.3s ease, box-shadow 0.3s ease;
transition: box-shadow 0.2s ease;
}
.academy-img-hover:hover {
transform: scale(1.05);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.academy-img-wrap {
overflow: hidden;
border-radius: 0.75rem;
}
/* hover 프리뷰 오버레이 */
#hover-preview {
display: none;
position: fixed;
inset: 0;
z-index: 45;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(3px);
pointer-events: none;
}
#hover-preview.is-active {
display: flex;
pointer-events: auto;
}
#hover-preview img {
max-height: 80vh;
max-width: 85vw;
border-radius: 0.75rem;
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.5);
opacity: 0;
transform: scale(0.3);
transition: opacity 0.25s ease, transform 0.25s ease;
}
#hover-preview.is-active img {
opacity: 1;
transform: scale(1);
}
#hover-preview .hover-caption {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
color: rgba(255,255,255,0.85);
font-size: 0.8rem;
background: rgba(0,0,0,0.5);
padding: 0.4rem 1rem;
border-radius: 2rem;
white-space: nowrap;
opacity: 0;
transition: opacity 0.3s ease 0.15s;
}
#hover-preview.is-active .hover-caption {
opacity: 1;
}
/* 클릭 라이트박스 */
#lightbox {
display: none;
position: fixed;
@@ -22,7 +71,7 @@
z-index: 50;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.85);
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(4px);
}
#lightbox.is-open {
@@ -1084,7 +1133,13 @@ class="rounded-lg cursor-pointer academy-img-hover"
</div>
</div>
<!-- 이미지 라이트박스 -->
<!-- hover 프리뷰 오버레이 -->
<div id="hover-preview">
<img id="hover-preview-img" src="" alt="">
<span class="hover-caption" id="hover-preview-caption"></span>
</div>
<!-- 클릭 라이트박스 -->
<div id="lightbox" onclick="closeLightbox()">
<button onclick="closeLightbox()" style="position:absolute; top:1rem; right:1rem; background:none; border:none; cursor:pointer; color:rgba(255,255,255,0.8); padding:0.5rem;">
<svg style="width:2rem; height:2rem;" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>
@@ -1092,21 +1147,90 @@ class="rounded-lg cursor-pointer academy-img-hover"
<img id="lightbox-img" onclick="event.stopPropagation()">
</div>
<script>
function openLightbox(el) {
var lb = document.getElementById('lightbox');
var img = document.getElementById('lightbox-img');
img.src = el.src;
img.alt = el.alt;
lb.classList.add('is-open');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
var lb = document.getElementById('lightbox');
lb.classList.remove('is-open');
document.body.style.overflow = '';
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeLightbox();
});
(function() {
var preview = document.getElementById('hover-preview');
var previewImg = document.getElementById('hover-preview-img');
var previewCaption = document.getElementById('hover-preview-caption');
var hoverTimer = null;
var isPreviewActive = false;
var HOVER_DELAY = 350;
// 모든 academy 이미지에 hover 프리뷰 바인딩
document.querySelectorAll('.academy-img-hover').forEach(function(img) {
img.addEventListener('mouseenter', function() {
var el = this;
hoverTimer = setTimeout(function() {
showPreview(el);
}, HOVER_DELAY);
});
img.addEventListener('mouseleave', function() {
clearTimeout(hoverTimer);
// 프리뷰가 활성화 된 상태가 아니면 아무것도 안함
// 프리뷰 위에 마우스가 있으면 프리뷰가 유지됨
if (!isPreviewActive) return;
// 짧은 딜레이 후 마우스가 프리뷰 위에 없으면 닫기
setTimeout(function() {
if (!preview.matches(':hover')) {
hidePreview();
}
}, 100);
});
});
// 프리뷰 오버레이에서 마우스가 벗어나면 닫기
preview.addEventListener('mouseleave', function() {
hidePreview();
});
// 프리뷰 클릭 시 라이트박스로 전환
preview.addEventListener('click', function() {
hidePreview();
openLightbox(previewImg);
});
function showPreview(el) {
previewImg.src = el.src;
previewImg.alt = el.alt || '';
// 캡션: 이미지 다음 형제 p 태그 또는 alt 텍스트
var caption = el.alt || '';
var nextP = el.parentElement && el.parentElement.querySelector('p');
if (nextP) caption = nextP.textContent;
previewCaption.textContent = caption;
preview.classList.add('is-active');
isPreviewActive = true;
}
function hidePreview() {
preview.classList.remove('is-active');
isPreviewActive = false;
}
// 클릭 라이트박스
window.openLightbox = function(el) {
var lb = document.getElementById('lightbox');
var img = document.getElementById('lightbox-img');
img.src = el.src;
img.alt = el.alt;
lb.classList.add('is-open');
document.body.style.overflow = 'hidden';
// hover 프리뷰가 열려있으면 닫기
hidePreview();
};
window.closeLightbox = function() {
var lb = document.getElementById('lightbox');
lb.classList.remove('is-open');
document.body.style.overflow = '';
};
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
if (isPreviewActive) hidePreview();
closeLightbox();
}
});
})();
</script>
@endsection