mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:27:09 -05: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:
		
							parent
							
								
									f9fbf1a2a5
								
							
						
					
					
						commit
						48e4ea5231
					
				
							
								
								
									
										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
 | 
						// eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
	interface HTMLAttributes<T> {
 | 
						interface HTMLAttributes<T> {
 | 
				
			||||||
		'on:copyImage'?: () => void;
 | 
							'on:copyImage'?: () => void;
 | 
				
			||||||
 | 
							'on:zoomImage'?: () => void;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,14 +11,18 @@
 | 
				
			|||||||
	import Heart from 'svelte-material-icons/Heart.svelte';
 | 
						import Heart from 'svelte-material-icons/Heart.svelte';
 | 
				
			||||||
	import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
 | 
						import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
 | 
				
			||||||
	import InformationOutline from 'svelte-material-icons/InformationOutline.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 MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
 | 
				
			||||||
	import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
 | 
						import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
 | 
				
			||||||
	import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
 | 
						import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
 | 
				
			||||||
	import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
 | 
						import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
 | 
				
			||||||
	import MenuOption from '../shared-components/context-menu/menu-option.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 asset: AssetResponseDto;
 | 
				
			||||||
	export let showCopyButton: boolean;
 | 
						export let showCopyButton: boolean;
 | 
				
			||||||
 | 
						export let showZoomButton: boolean;
 | 
				
			||||||
	export let showMotionPlayButton: boolean;
 | 
						export let showMotionPlayButton: boolean;
 | 
				
			||||||
	export let isMotionPhotoPlaying = false;
 | 
						export let isMotionPhotoPlaying = false;
 | 
				
			||||||
	export let showDownloadButton: boolean;
 | 
						export let showDownloadButton: boolean;
 | 
				
			||||||
@ -65,6 +69,20 @@
 | 
				
			|||||||
				/>
 | 
									/>
 | 
				
			||||||
			{/if}
 | 
								{/if}
 | 
				
			||||||
		{/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}
 | 
							{#if showCopyButton}
 | 
				
			||||||
			<CircleIconButton
 | 
								<CircleIconButton
 | 
				
			||||||
				isOpacity={true}
 | 
									isOpacity={true}
 | 
				
			||||||
 | 
				
			|||||||
@ -308,6 +308,7 @@
 | 
				
			|||||||
			{asset}
 | 
								{asset}
 | 
				
			||||||
			isMotionPhotoPlaying={shouldPlayMotionPhoto}
 | 
								isMotionPhotoPlaying={shouldPlayMotionPhoto}
 | 
				
			||||||
			showCopyButton={canCopyImagesToClipboard && asset.type === AssetTypeEnum.Image}
 | 
								showCopyButton={canCopyImagesToClipboard && asset.type === AssetTypeEnum.Image}
 | 
				
			||||||
 | 
								showZoomButton={asset.type === AssetTypeEnum.Image}
 | 
				
			||||||
			showMotionPlayButton={!!asset.livePhotoVideoId}
 | 
								showMotionPlayButton={!!asset.livePhotoVideoId}
 | 
				
			||||||
			showDownloadButton={shouldShowDownloadButton}
 | 
								showDownloadButton={shouldShowDownloadButton}
 | 
				
			||||||
			on:goBack={closeViewer}
 | 
								on:goBack={closeViewer}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@
 | 
				
			|||||||
		NotificationType
 | 
							NotificationType
 | 
				
			||||||
	} from '../shared-components/notification/notification';
 | 
						} from '../shared-components/notification/notification';
 | 
				
			||||||
	import { useZoomImageWheel } from '@zoom-image/svelte';
 | 
						import { useZoomImageWheel } from '@zoom-image/svelte';
 | 
				
			||||||
 | 
						import { photoZoomState } from '$lib/stores/zoom-image.store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export let asset: AssetResponseDto;
 | 
						export let asset: AssetResponseDto;
 | 
				
			||||||
	export let publicSharedKey = '';
 | 
						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) {
 | 
						$: if (imgElement) {
 | 
				
			||||||
		createZoomImageWheel(imgElement, {
 | 
							createZoomImageWheel(imgElement, {
 | 
				
			||||||
			wheelZoomRatio: 0.06
 | 
								wheelZoomRatio: 0.06
 | 
				
			||||||
@ -81,7 +97,7 @@
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} />
 | 
					<svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} on:zoomImage={doZoomImage} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div
 | 
					<div
 | 
				
			||||||
	transition:fade={{ duration: 150 }}
 | 
						transition:fade={{ duration: 150 }}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@
 | 
				
			|||||||
	export let title = '';
 | 
						export let title = '';
 | 
				
			||||||
	export let isOpacity = false;
 | 
						export let isOpacity = false;
 | 
				
			||||||
	export let forceDark = false;
 | 
						export let forceDark = false;
 | 
				
			||||||
 | 
						export let hideMobile = false;
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<button
 | 
					<button
 | 
				
			||||||
@ -17,7 +18,8 @@
 | 
				
			|||||||
	class:dark:text-immich-dark-fg={!forceDark}
 | 
						class:dark:text-immich-dark-fg={!forceDark}
 | 
				
			||||||
	class="rounded-full p-3 flex place-items-center place-content-center transition-all
 | 
						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'}
 | 
						{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
 | 
						on:click
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
	<svelte:component this={logo} {size} />
 | 
						<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>();
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user