mirror of
				https://github.com/imfing/hextra.git
				synced 2025-10-31 12:54:51 -04:00 
			
		
		
		
	chore(image-zoom): enhance zoom functionality with improved transitions and closing behavior
- Updated CSS for smoother transitions and added closing effects for the zoom overlay. - Enhanced JavaScript to support dedicated closing transitions and improved event handling for dismissing the overlay. - Removed unnecessary scroll lock and overflow styles for better user experience.
This commit is contained in:
		| @@ -1,4 +1,3 @@ | ||||
| /* Minimal styles for Hextra image zoom overlay */ | ||||
| .hextra-zoom-image-overlay { | ||||
|   position: fixed; | ||||
|   inset: 0; | ||||
| @@ -8,27 +7,40 @@ | ||||
|   justify-content: center; | ||||
|   z-index: 9999; | ||||
|   opacity: 0; | ||||
|   transition: opacity 0.25s ease-out; | ||||
|   transition: opacity 260ms cubic-bezier(0.2, 0, 0, 1); | ||||
|   cursor: zoom-out; | ||||
|   overscroll-behavior: contain; | ||||
|   touch-action: none; | ||||
|   overscroll-behavior: auto; | ||||
|   touch-action: auto; | ||||
|   backdrop-filter: blur(var(--hextra-image-zoom-blur, 4px)); | ||||
|   -webkit-backdrop-filter: blur(var(--hextra-image-zoom-blur, 4px)); | ||||
| } | ||||
|  | ||||
| .hextra-zoom-image-overlay.show { | ||||
|   opacity: 1; | ||||
| } | ||||
|  | ||||
| .hextra-zoom-image-overlay.closing { | ||||
|   opacity: 0; | ||||
|   transition: opacity 360ms cubic-bezier(0.2, 0, 0, 1); | ||||
| } | ||||
|  | ||||
| .hextra-zoom-image { | ||||
|   max-width: min(95vw, 1200px); | ||||
|   max-height: 95vh; | ||||
|   border-radius: 8px; | ||||
|   box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35); | ||||
|   transition: transform 0.3s ease-out; | ||||
|   will-change: transform; | ||||
|   transform: scale(0.98); | ||||
| } | ||||
|  | ||||
| .hextra-zoom-image-overlay.show .hextra-zoom-image { | ||||
|   transform: scale(1); | ||||
|   transition: transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1); | ||||
| } | ||||
|  | ||||
| .hextra-zoom-image-overlay.closing .hextra-zoom-image { | ||||
|   transform: scale(0.98); | ||||
|   transition: transform 340ms cubic-bezier(0.3, 0, 0.2, 1); | ||||
| } | ||||
|  | ||||
| @media (prefers-reduced-motion: reduce) { | ||||
| @@ -42,9 +54,3 @@ | ||||
| .content img:not([data-no-zoom]) { | ||||
|   cursor: zoom-in; | ||||
| } | ||||
|  | ||||
| html:has(.hextra-zoom-image-overlay.show), | ||||
| body:has(.hextra-zoom-image-overlay.show) { | ||||
|   overflow: hidden; | ||||
|   height: 100%; | ||||
| } | ||||
|   | ||||
| @@ -1,16 +1,14 @@ | ||||
| // Minimal, dependency-free image zoom for Hextra | ||||
| // - Activates on images inside `.content` | ||||
| // - Close on overlay click or Escape | ||||
| // - Opt-out with `data-no-zoom` on <img> | ||||
| /*! | ||||
|  * Hextra Image Zoom | ||||
|  * - Zooms images inside `.content` into a dark, blurred overlay. | ||||
|  * - Dismiss: overlay click, Esc, wheel/scroll (non-ctrl). | ||||
|  * - Pinch/trackpad pinch (wheel+ctrl) will NOT dismiss. | ||||
|  * - Opt out per image via `data-no-zoom`. | ||||
|  * - Customize via CSS vars: --hextra-image-zoom-backdrop, --hextra-image-zoom-blur. | ||||
|  */ | ||||
|  | ||||
| (function () { | ||||
|   function ready(fn) { | ||||
|     if (document.readyState === "loading") { | ||||
|       document.addEventListener("DOMContentLoaded", fn, { once: true }); | ||||
|     } else { | ||||
|       fn(); | ||||
|     } | ||||
|   } | ||||
|   'use strict'; | ||||
|  | ||||
|   function createOverlay(src, alt) { | ||||
|     const overlay = document.createElement("div"); | ||||
| @@ -25,33 +23,41 @@ | ||||
|  | ||||
|     overlay.appendChild(img); | ||||
|  | ||||
|     function close() { | ||||
|       overlay.classList.remove("show"); | ||||
|       document.documentElement.style.removeProperty("overflow"); | ||||
|     function close(immediate = false) { | ||||
|       // trigger dedicated closing transitions for smoother zoom-out | ||||
|       overlay.classList.add("closing"); | ||||
|       window.removeEventListener("keydown", onKeyDown, true); | ||||
|       overlay.addEventListener( | ||||
|         "transitionend", | ||||
|         () => overlay.remove(), | ||||
|         { once: true } | ||||
|       ); | ||||
|       window.removeEventListener("scroll", onScroll, true); | ||||
|       overlay.removeEventListener("wheel", onWheel); | ||||
|  | ||||
|       if (immediate) { | ||||
|         overlay.remove(); | ||||
|         return; | ||||
|       } | ||||
|       overlay.addEventListener("transitionend", () => overlay.remove(), { once: true }); | ||||
|     } | ||||
|  | ||||
|     function onKeyDown(e) { | ||||
|       if (e.key === "Escape") close(); | ||||
|     } | ||||
|  | ||||
|     overlay.addEventListener("click", close, { once: true }); | ||||
|     overlay.addEventListener("click", () => close(false), { once: true }); | ||||
|     window.addEventListener("keydown", onKeyDown, true); | ||||
|  | ||||
|     function onWheel(e) { if (e && e.ctrlKey) return; close(true); } | ||||
|     function onScroll() { close(true); } | ||||
|  | ||||
|     overlay.addEventListener("wheel", onWheel, { passive: true }); | ||||
|     window.addEventListener("scroll", onScroll, true); | ||||
|  | ||||
|     document.body.appendChild(overlay); | ||||
|     // lock scroll | ||||
|     document.documentElement.style.overflow = "hidden"; | ||||
|  | ||||
|     // trigger fade-in | ||||
|     requestAnimationFrame(() => overlay.classList.add("show")); | ||||
|   } | ||||
|  | ||||
|   ready(function () { | ||||
|   // Initialize after DOM is parsed; defer script ensures this usually fires immediately | ||||
|   document.addEventListener('DOMContentLoaded', function () { | ||||
|     const container = document.querySelector(".content"); | ||||
|     if (!container) return; | ||||
|  | ||||
| @@ -72,5 +78,5 @@ | ||||
|       }, | ||||
|       true | ||||
|     ); | ||||
|   }); | ||||
|   }, { once: true }); | ||||
| })(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Xin
					Xin