From 6c37feafcd2c8828cb5184fe743d0bc5d5e1eaef Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Sun, 23 Aug 2026 21:42:43 +0200 Subject: [PATCH 1/2] fix(Images): do not show drag cursor when zoom is disabled pointerDown() set dragging = true unconditionally, unlike updateZoom(), pointerMove() and onDblclick() which all early-return on !canZoom. Combined with the .dragging { cursor: move } style, this showed a move cursor on embedded previews implying they could be panned, even though pointerMove() only pans when zoomRatio > 1, which can never happen while canZoom is false (the Files widget's setting). This does not enable zoom or panning; it only removes a false affordance. Assisted-by: Claude Sonnet 5:claude-sonnet-5 Signed-off-by: Jos Poortvliet --- src/components/Images.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Images.vue b/src/components/Images.vue index dd07e1441..4d31001c4 100644 --- a/src/components/Images.vue +++ b/src/components/Images.vue @@ -324,6 +324,9 @@ export default { * @param {DragEvent} event the event */ pointerDown(event) { + if (!this.canZoom) { + return + } // New pointer - mouse down or additional touch --> store client coordinates in the pointer cache this.pointerCache.push({ pointerId: event.pointerId, x: event.clientX, y: event.clientY }) From 63a13b52f4b96d125e50c53e7c79748d04cc2601 Mon Sep 17 00:00:00 2001 From: Jos Poortvliet Date: Sun, 23 Aug 2026 22:39:41 +0200 Subject: [PATCH 2/2] fix(Images): stop capturing wheel/touch input when zoom is disabled Follow-up to 6c37feaf. Same root cause, two more spots: the component unconditionally claimed a user input, then bailed out in the handler after the input was already consumed. - wheel: @wheel.stop.prevent called preventDefault()/stopPropagation() before updateZoom() ever checked canZoom, so the embedded preview swallowed page scroll even though it can't zoom. Moved the modifiers into updateZoom() itself, after the canZoom guard, so the browser's default scroll runs unless zoom is actually enabled. - touch-action: the img/video rule set touch-action: none unconditionally, which blocks swipe-to-scroll on touch devices the same way the wheel handler blocked mouse scroll. Scoped it to a new &.canZoom class bound to the existing canZoom prop, so it only applies where panning/pinch-zoom is actually available. Also fixed the mixed tabs/spaces left in pointerDown()'s guard from the previous commit. Verified canZoom is true only for the active file in the Viewer modal (src/views/Viewer.vue:145) and false for the embedded/single-file path (:17) and comparison view (:111), so modal zoom/pan/scroll-lock is unchanged; only embedded previews (e.g. the Smart Picker file-link widget in Text) gain back normal page scroll. Assisted-by: Claude Sonnet 5:claude-sonnet-5 Tested in Talk & Text, viewer and embedded. You can now scroll over images ;-) Signed-off-by: Jos Poortvliet --- src/components/Images.vue | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/components/Images.vue b/src/components/Images.vue index 4d31001c4..6103cbe8e 100644 --- a/src/components/Images.vue +++ b/src/components/Images.vue @@ -18,13 +18,14 @@ :class="{ dragging, loaded, - zoomed: zoomRatio > 1 + zoomed: zoomRatio > 1, + canZoom }" :src="data" :style="imgStyle" @error.capture.prevent.stop.once="onFail" @load="updateImgSize" - @wheel.stop.prevent="updateZoom" + @wheel="updateZoom" @dblclick.prevent="onDblclick" @pointerdown.prevent="pointerDown" @pointerup.prevent="pointerUp" @@ -36,7 +37,8 @@ :class="{ dragging, loaded, - zoomed: zoomRatio > 1 + zoomed: zoomRatio > 1, + canZoom }" :style="imgStyle" :playsinline="true" @@ -45,7 +47,7 @@ preload="metadata" @canplaythrough="doneLoadingLivePhoto" @loadedmetadata="updateImgSize" - @wheel.stop.prevent="updateZoom" + @wheel="updateZoom" @error.capture.prevent.stop.once="onFail" @dblclick.prevent="onDblclick" @pointerdown.prevent="pointerDown" @@ -293,6 +295,8 @@ export default { if (!this.canZoom) { return } + event.stopPropagation() + event.preventDefault() const isZoomIn = event.deltaY < 0 const newZoomRatio = isZoomIn @@ -325,8 +329,8 @@ export default { */ pointerDown(event) { if (!this.canZoom) { - return - } + return + } // New pointer - mouse down or additional touch --> store client coordinates in the pointer cache this.pointerCache.push({ pointerId: event.pointerId, x: event.clientX, y: event.clientY }) @@ -472,7 +476,6 @@ img, video { background-color: #000; // disable animations during zooming/resize transition: none !important; - touch-action: none; // show checkered bg on hover if not currently zooming (but ok if zoomed) &:hover { background-image: linear-gradient(45deg, #{$checkered-color} 25%, transparent 25%), @@ -495,6 +498,13 @@ img, video { transition: none !important; cursor: move; } + + // only claim wheel/touch gestures when zoom is actually available; + // otherwise let the browser scroll the page as normal (canZoom=false + // in embedded previews, e.g. the Smart Picker file-link widget) + &.canZoom { + touch-action: none; + } } .live-photo_play_button {