Something went wrong. Try again.
Fork of Chiri for Astro for my blog forked from quillmatiq.com/augment
Something went wrong. Try again.
4.0 kB · 148 lines
Astro
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149<div id="image-viewer" class="image-viewer"> <img id="image-viewer-img" src="" alt="" /></div>
<script> function initImageViewer() { const viewer = document.getElementById('image-viewer') const viewerImg = document.getElementById('image-viewer-img') as HTMLImageElement
if (!viewer || !viewerImg || viewerImg.tagName !== 'IMG') return
// Display image in fullscreen viewer overlay function showImage(src: string, alt?: string) { if (viewerImg && src) { viewerImg.src = src viewerImg.alt = alt || '' } // Show visibility first viewer!.style.visibility = 'visible' void viewer!.offsetWidth viewer!.classList.add('active') document.body.classList.add('image-viewer-open') document.body.style.overflow = 'hidden' document.body.dataset.scrollY = window.scrollY.toString() viewer!.style.cursor = 'auto' setTimeout(() => { viewer!.style.cursor = '' }, 10) }
// Hide the image viewer and restore page scroll function hideImage() { viewer!.classList.remove('active') document.body.classList.remove('image-viewer-open') document.body.style.overflow = '' }
// Hide and clear image after transition ends viewer!.addEventListener('transitionend', (e) => { if (e.propertyName === 'opacity' && !viewer!.classList.contains('active')) { viewer!.style.visibility = 'hidden' if (viewerImg) { viewerImg.src = '' viewerImg.alt = '' } viewer!.style.cursor = 'auto' setTimeout(() => { viewer!.style.cursor = '' }, 10) } })
// Bind click events to images with data-preview="true" attribute function bindImageClickEvents() { const previewImages = document.querySelectorAll('img[data-preview="true"]') previewImages.forEach((img) => { const imgElement = img as HTMLImageElement imgElement.style.cursor = 'pointer' imgElement.addEventListener('click', (e) => { e.preventDefault() const target = e.target as HTMLImageElement showImage(target.src, target.alt || '') }) }) }
viewer?.addEventListener('click', hideImage)
// Prevent touch scroll in image viewer viewer?.addEventListener( 'touchmove', (e) => { if (viewer.classList.contains('active')) { e.preventDefault() } }, { passive: false } )
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && viewer.classList.contains('active')) { hideImage() } })
bindImageClickEvents()
// Observe only the content area instead of the entire body const contentArea = document.querySelector('.prose') || document.querySelector('.content') || document.querySelector('article') if (contentArea) { const observer = new MutationObserver(() => { bindImageClickEvents() })
observer.observe(contentArea, { childList: true, subtree: true }) }
// Hide initially viewer!.style.visibility = 'hidden' }
// Use only astro:page-load as it fires on initial load and navigation document.addEventListener('astro:page-load', initImageViewer)</script>
<style> .image-viewer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.15s ease-in-out; background: color-mix(in srgb, var(--bg) 90%, transparent); cursor: zoom-out; }
.image-viewer.active { opacity: 1; }
.image-viewer img { min-width: 45rem; max-width: 60vw; max-height: 80vh; object-fit: contain; cursor: zoom-out; }
@media (max-width: 768px) { .image-viewer img { min-width: 100vw; } }
body.image-viewer-open { overflow: hidden; }</style>