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 { | .hextra-zoom-image-overlay { | ||||||
|   position: fixed; |   position: fixed; | ||||||
|   inset: 0; |   inset: 0; | ||||||
| @@ -8,27 +7,40 @@ | |||||||
|   justify-content: center; |   justify-content: center; | ||||||
|   z-index: 9999; |   z-index: 9999; | ||||||
|   opacity: 0; |   opacity: 0; | ||||||
|   transition: opacity 0.25s ease-out; |   transition: opacity 260ms cubic-bezier(0.2, 0, 0, 1); | ||||||
|   cursor: zoom-out; |   cursor: zoom-out; | ||||||
|   overscroll-behavior: contain; |   overscroll-behavior: auto; | ||||||
|   touch-action: none; |   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 { | .hextra-zoom-image-overlay.show { | ||||||
|   opacity: 1; |   opacity: 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .hextra-zoom-image-overlay.closing { | ||||||
|  |   opacity: 0; | ||||||
|  |   transition: opacity 360ms cubic-bezier(0.2, 0, 0, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
| .hextra-zoom-image { | .hextra-zoom-image { | ||||||
|   max-width: min(95vw, 1200px); |   max-width: min(95vw, 1200px); | ||||||
|   max-height: 95vh; |   max-height: 95vh; | ||||||
|   border-radius: 8px; |   border-radius: 8px; | ||||||
|   box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35); |   box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35); | ||||||
|   transition: transform 0.3s ease-out; |   will-change: transform; | ||||||
|   transform: scale(0.98); |   transform: scale(0.98); | ||||||
| } | } | ||||||
|  |  | ||||||
| .hextra-zoom-image-overlay.show .hextra-zoom-image { | .hextra-zoom-image-overlay.show .hextra-zoom-image { | ||||||
|   transform: scale(1); |   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) { | @media (prefers-reduced-motion: reduce) { | ||||||
| @@ -42,9 +54,3 @@ | |||||||
| .content img:not([data-no-zoom]) { | .content img:not([data-no-zoom]) { | ||||||
|   cursor: zoom-in; |   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` |  * Hextra Image Zoom | ||||||
| // - Close on overlay click or Escape |  * - Zooms images inside `.content` into a dark, blurred overlay. | ||||||
| // - Opt-out with `data-no-zoom` on <img> |  * - 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 () { | ||||||
|   function ready(fn) { |   'use strict'; | ||||||
|     if (document.readyState === "loading") { |  | ||||||
|       document.addEventListener("DOMContentLoaded", fn, { once: true }); |  | ||||||
|     } else { |  | ||||||
|       fn(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   function createOverlay(src, alt) { |   function createOverlay(src, alt) { | ||||||
|     const overlay = document.createElement("div"); |     const overlay = document.createElement("div"); | ||||||
| @@ -25,33 +23,41 @@ | |||||||
|  |  | ||||||
|     overlay.appendChild(img); |     overlay.appendChild(img); | ||||||
|  |  | ||||||
|     function close() { |     function close(immediate = false) { | ||||||
|       overlay.classList.remove("show"); |       // trigger dedicated closing transitions for smoother zoom-out | ||||||
|       document.documentElement.style.removeProperty("overflow"); |       overlay.classList.add("closing"); | ||||||
|       window.removeEventListener("keydown", onKeyDown, true); |       window.removeEventListener("keydown", onKeyDown, true); | ||||||
|       overlay.addEventListener( |       window.removeEventListener("scroll", onScroll, true); | ||||||
|         "transitionend", |       overlay.removeEventListener("wheel", onWheel); | ||||||
|         () => overlay.remove(), |  | ||||||
|         { once: true } |       if (immediate) { | ||||||
|       ); |         overlay.remove(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       overlay.addEventListener("transitionend", () => overlay.remove(), { once: true }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function onKeyDown(e) { |     function onKeyDown(e) { | ||||||
|       if (e.key === "Escape") close(); |       if (e.key === "Escape") close(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     overlay.addEventListener("click", close, { once: true }); |     overlay.addEventListener("click", () => close(false), { once: true }); | ||||||
|     window.addEventListener("keydown", onKeyDown, 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); |     document.body.appendChild(overlay); | ||||||
|     // lock scroll |  | ||||||
|     document.documentElement.style.overflow = "hidden"; |  | ||||||
|  |  | ||||||
|     // trigger fade-in |     // trigger fade-in | ||||||
|     requestAnimationFrame(() => overlay.classList.add("show")); |     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"); |     const container = document.querySelector(".content"); | ||||||
|     if (!container) return; |     if (!container) return; | ||||||
|  |  | ||||||
| @@ -72,5 +78,5 @@ | |||||||
|       }, |       }, | ||||||
|       true |       true | ||||||
|     ); |     ); | ||||||
|   }); |   }, { once: true }); | ||||||
| })(); | })(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Xin
					Xin