From 4a7c988f542d31d1891d9320fa7cf61d6c4c0945 Mon Sep 17 00:00:00 2001 From: carlobortolan Date: Wed, 15 Jan 2025 19:23:55 +0100 Subject: [PATCH] Add viewerjs support --- package.json | 3 +- pnpm-lock.yaml | 8 +++ src/app/p/[photoId]/page.tsx | 9 ++- src/components/image/ImageLarge.tsx | 1 - src/components/image/ImageWithFallback.tsx | 65 ++++++++++++++++++---- src/components/image/index.ts | 1 + src/photo/PhotoDetailPage.tsx | 3 + src/photo/PhotoLarge.tsx | 3 + 8 files changed, 78 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 9816e848..ec73a2d2 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,8 @@ "sonner": "^1.7.1", "swr": "^2.3.0", "ts-exif-parser": "^0.2.2", - "use-debounce": "^10.0.4" + "use-debounce": "^10.0.4", + "viewerjs": "^1.11.7" }, "devDependencies": { "@next/bundle-analyzer": "15.1.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3042825e..47842bd8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,6 +104,9 @@ importers: use-debounce: specifier: ^10.0.4 version: 10.0.4(react@19.0.0) + viewerjs: + specifier: ^1.11.7 + version: 1.11.7 devDependencies: '@next/bundle-analyzer': specifier: 15.1.4 @@ -4255,6 +4258,9 @@ packages: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} + viewerjs@1.11.7: + resolution: {integrity: sha512-0JuVqOmL5v1jmEAlG5EBDR3XquxY8DWFQbFMprOXgaBB0F7Q/X9xWdEaQc59D8xzwkdUgXEMSSknTpriq95igg==} + vue@3.4.27: resolution: {integrity: sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==} peerDependencies: @@ -9467,6 +9473,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + viewerjs@1.11.7: {} + vue@3.4.27(typescript@5.7.3): dependencies: '@vue/compiler-dom': 3.4.27 diff --git a/src/app/p/[photoId]/page.tsx b/src/app/p/[photoId]/page.tsx index decfb273..26faa932 100644 --- a/src/app/p/[photoId]/page.tsx +++ b/src/app/p/[photoId]/page.tsx @@ -77,6 +77,13 @@ export default async function PhotoPage({ if (!photo) { redirect(PATH_ROOT); } return ( - + ); } diff --git a/src/components/image/ImageLarge.tsx b/src/components/image/ImageLarge.tsx index d7d178d0..18569d92 100644 --- a/src/components/image/ImageLarge.tsx +++ b/src/components/image/ImageLarge.tsx @@ -13,7 +13,6 @@ export default function ImageLarge(props: ImageProps) { blurCompatibilityLevel: blurCompatibilityMode ? 'high' : 'none', width: IMAGE_WIDTH_LARGE, height: Math.round(IMAGE_WIDTH_LARGE / aspectRatio), - allowFullscreen: true, }} /> ); }; diff --git a/src/components/image/ImageWithFallback.tsx b/src/components/image/ImageWithFallback.tsx index 0143c3f8..07279f87 100644 --- a/src/components/image/ImageWithFallback.tsx +++ b/src/components/image/ImageWithFallback.tsx @@ -3,15 +3,18 @@ /* eslint-disable jsx-a11y/alt-text */ import { BLUR_ENABLED } from '@/site/config'; import { useAppState } from '@/state/AppState'; -import { clsx} from 'clsx/lite'; +import { clsx } from 'clsx/lite'; import Image, { ImageProps } from 'next/image'; import { useCallback, useEffect, useRef, useState } from 'react'; import FullscreenButton from '../FullscreenButton'; +import Viewer from 'viewerjs'; +import 'viewerjs/dist/viewer.css'; export default function ImageWithFallback(props: ImageProps & { blurCompatibilityLevel?: 'none' | 'low' | 'high' imgClassName?: string allowFullscreen?: boolean + enableImageActions?: boolean }) { const { className, @@ -19,7 +22,7 @@ export default function ImageWithFallback(props: ImageProps & { blurDataURL, blurCompatibilityLevel = 'low', imgClassName = 'object-cover h-full', - allowFullscreen, + enableImageActions = false, ...rest } = props; @@ -34,7 +37,10 @@ export default function ImageWithFallback(props: ImageProps & { const [hideFallback, setHideFallback] = useState(false); - const imgRef = useRef(null); + const containerRef = useRef(null); + const viewerRef = useRef(null); + const imgRef = useRef(null); + const { isFullscreen } = useAppState(); useEffect(() => { const timeout = setTimeout( @@ -53,6 +59,37 @@ export default function ImageWithFallback(props: ImageProps & { } }, [isLoading, didError]); + useEffect(() => { + if (containerRef.current && enableImageActions) { + viewerRef.current = new Viewer(containerRef.current, { + inline: false, + button: true, + navbar: false, + title: false, + toolbar: { + zoomIn: 1, + zoomOut: 1, + oneToOne: 1, + reset: 1, + prev: 0, + play: { + show: 0, + size: 'large', + }, + next: 0, + rotateLeft: 1, + rotateRight: 1, + flipHorizontal: 1, + flipVertical: 1, + tooltip: 1, + }, + }); + return () => { + viewerRef.current?.destroy(); + }; + } + }, [enableImageActions]); + const showFallback = !wasCached && !hideFallback; @@ -73,6 +110,7 @@ export default function ImageWithFallback(props: ImageProps & { className, 'flex relative', )} + ref={containerRef} > {(showFallback || shouldDebugImageFallbacks) &&
}
} - - {allowFullscreen && } + + {enableImageActions && } ); } diff --git a/src/components/image/index.ts b/src/components/image/index.ts index eb7d6582..8a46d1ac 100644 --- a/src/components/image/index.ts +++ b/src/components/image/index.ts @@ -14,4 +14,5 @@ export interface ImageProps { alt: string blurDataURL?: string priority?: boolean + enableImageActions?: boolean } diff --git a/src/photo/PhotoDetailPage.tsx b/src/photo/PhotoDetailPage.tsx index beb67cf4..da945e7e 100644 --- a/src/photo/PhotoDetailPage.tsx +++ b/src/photo/PhotoDetailPage.tsx @@ -25,6 +25,7 @@ export default function PhotoDetailPage({ dateRange, shouldShare, includeFavoriteInAdminMenu, + enableImageActions, }: { photo: Photo photos: Photo[] @@ -34,6 +35,7 @@ export default function PhotoDetailPage({ dateRange?: PhotoDateRange shouldShare?: boolean includeFavoriteInAdminMenu?: boolean + enableImageActions?: boolean } & PhotoSetCategory) { let customHeader: JSX.Element | undefined; @@ -112,6 +114,7 @@ export default function PhotoDetailPage({ shouldShareSimulation={simulation !== undefined} shouldScrollOnShare={false} includeFavoriteInAdminMenu={includeFavoriteInAdminMenu} + enableImageActions={enableImageActions} />, ]} /> diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index 32befc1b..f4608afb 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -55,6 +55,7 @@ export default function PhotoLarge({ shouldShareFocalLength, includeFavoriteInAdminMenu, onVisible, + enableImageActions = false, }: { photo: Photo className?: string @@ -75,6 +76,7 @@ export default function PhotoLarge({ shouldScrollOnShare?: boolean includeFavoriteInAdminMenu?: boolean onVisible?: () => void + enableImageActions?: boolean }) { const ref = useRef(null); @@ -143,6 +145,7 @@ export default function PhotoLarge({ blurDataURL={photo.blurData} blurCompatibilityMode={doesPhotoNeedBlurCompatibility(photo)} priority={priority} + enableImageActions={enableImageActions} /> }