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
6 changed files with 45 additions and 3 deletions
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…
Reference in a new issue