mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	feat(web): add zoom toggle icon (#2873)
* feat(web): add zoom toggle icon * update zoom-image dependency * fix lint issues * remove variable testing line * Simplify code using ternary conditional Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> * fix typo --------- Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										1
									
								
								web/src/app.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								web/src/app.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -29,5 +29,6 @@ declare namespace svelteHTML {
 | 
			
		||||
	// eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
	interface HTMLAttributes<T> {
 | 
			
		||||
		'on:copyImage'?: () => void;
 | 
			
		||||
		'on:zoomImage'?: () => void;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,14 +11,18 @@
 | 
			
		||||
	import Heart from 'svelte-material-icons/Heart.svelte';
 | 
			
		||||
	import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
 | 
			
		||||
	import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
 | 
			
		||||
	import MagnifyPlusOutline from 'svelte-material-icons/MagnifyPlusOutline.svelte';
 | 
			
		||||
	import MagnifyMinusOutline from 'svelte-material-icons/MagnifyMinusOutline.svelte';
 | 
			
		||||
	import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
 | 
			
		||||
	import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
 | 
			
		||||
	import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
 | 
			
		||||
	import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
 | 
			
		||||
	import MenuOption from '../shared-components/context-menu/menu-option.svelte';
 | 
			
		||||
	import { photoZoomState } from '$lib/stores/zoom-image.store';
 | 
			
		||||
 | 
			
		||||
	export let asset: AssetResponseDto;
 | 
			
		||||
	export let showCopyButton: boolean;
 | 
			
		||||
	export let showZoomButton: boolean;
 | 
			
		||||
	export let showMotionPlayButton: boolean;
 | 
			
		||||
	export let isMotionPhotoPlaying = false;
 | 
			
		||||
	export let showDownloadButton: boolean;
 | 
			
		||||
@@ -65,6 +69,20 @@
 | 
			
		||||
				/>
 | 
			
		||||
			{/if}
 | 
			
		||||
		{/if}
 | 
			
		||||
		{#if showZoomButton}
 | 
			
		||||
			<CircleIconButton
 | 
			
		||||
				isOpacity={true}
 | 
			
		||||
				hideMobile={true}
 | 
			
		||||
				logo={$photoZoomState && $photoZoomState.currentZoom > 1
 | 
			
		||||
					? MagnifyMinusOutline
 | 
			
		||||
					: MagnifyPlusOutline}
 | 
			
		||||
				title="Zoom Image"
 | 
			
		||||
				on:click={() => {
 | 
			
		||||
					const zoomImage = new CustomEvent('zoomImage');
 | 
			
		||||
					window.dispatchEvent(zoomImage);
 | 
			
		||||
				}}
 | 
			
		||||
			/>
 | 
			
		||||
		{/if}
 | 
			
		||||
		{#if showCopyButton}
 | 
			
		||||
			<CircleIconButton
 | 
			
		||||
				isOpacity={true}
 | 
			
		||||
 
 | 
			
		||||
@@ -308,6 +308,7 @@
 | 
			
		||||
			{asset}
 | 
			
		||||
			isMotionPhotoPlaying={shouldPlayMotionPhoto}
 | 
			
		||||
			showCopyButton={canCopyImagesToClipboard && asset.type === AssetTypeEnum.Image}
 | 
			
		||||
			showZoomButton={asset.type === AssetTypeEnum.Image}
 | 
			
		||||
			showMotionPlayButton={!!asset.livePhotoVideoId}
 | 
			
		||||
			showDownloadButton={shouldShowDownloadButton}
 | 
			
		||||
			on:goBack={closeViewer}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
		NotificationType
 | 
			
		||||
	} from '../shared-components/notification/notification';
 | 
			
		||||
	import { useZoomImageWheel } from '@zoom-image/svelte';
 | 
			
		||||
	import { photoZoomState } from '$lib/stores/zoom-image.store';
 | 
			
		||||
 | 
			
		||||
	export let asset: AssetResponseDto;
 | 
			
		||||
	export let publicSharedKey = '';
 | 
			
		||||
@@ -73,7 +74,22 @@
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const { createZoomImage: createZoomImageWheel } = useZoomImageWheel();
 | 
			
		||||
	const doZoomImage = async () => {
 | 
			
		||||
		setZoomImageWheelState({
 | 
			
		||||
			currentZoom: $zoomImageWheelState.currentZoom === 1 ? 2 : 1
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const {
 | 
			
		||||
		createZoomImage: createZoomImageWheel,
 | 
			
		||||
		zoomImageState: zoomImageWheelState,
 | 
			
		||||
		setZoomImageState: setZoomImageWheelState
 | 
			
		||||
	} = useZoomImageWheel();
 | 
			
		||||
 | 
			
		||||
	zoomImageWheelState.subscribe((state) => {
 | 
			
		||||
		photoZoomState.set(state);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	$: if (imgElement) {
 | 
			
		||||
		createZoomImageWheel(imgElement, {
 | 
			
		||||
			wheelZoomRatio: 0.06
 | 
			
		||||
@@ -81,7 +97,7 @@
 | 
			
		||||
	}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} />
 | 
			
		||||
<svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} on:zoomImage={doZoomImage} />
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
	transition:fade={{ duration: 150 }}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
	export let title = '';
 | 
			
		||||
	export let isOpacity = false;
 | 
			
		||||
	export let forceDark = false;
 | 
			
		||||
	export let hideMobile = false;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<button
 | 
			
		||||
@@ -17,7 +18,8 @@
 | 
			
		||||
	class:dark:text-immich-dark-fg={!forceDark}
 | 
			
		||||
	class="rounded-full p-3 flex place-items-center place-content-center transition-all
 | 
			
		||||
	{isOpacity ? 'hover:bg-immich-bg/30' : 'immich-circle-icon-button hover:dark:text-immich-dark-gray'}
 | 
			
		||||
  {forceDark && 'hover:text-black'}"
 | 
			
		||||
  {forceDark && 'hover:text-black'}
 | 
			
		||||
  {hideMobile && 'hidden sm:flex'}"
 | 
			
		||||
	on:click
 | 
			
		||||
>
 | 
			
		||||
	<svelte:component this={logo} {size} />
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								web/src/lib/stores/zoom-image.store.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								web/src/lib/stores/zoom-image.store.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
import type { ZoomImageWheelState } from '@zoom-image/core';
 | 
			
		||||
 | 
			
		||||
export const photoZoomState = writable<ZoomImageWheelState>();
 | 
			
		||||
		Reference in New Issue
	
	Block a user