diff --git a/src/app/layout.tsx b/src/app/layout.tsx index feeadc9a..fddaab5f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -23,6 +23,7 @@ import ShareModals from '@/share/ShareModals'; import '../site/globals.css'; import '../site/sonner.css'; +import '../site/viewerjs.css'; const ibmPlexMono = IBM_Plex_Mono({ subsets: ['latin'], diff --git a/src/components/image/ImageZoomControls.tsx b/src/components/image/ImageZoomControls.tsx deleted file mode 100644 index da9a3cd5..00000000 --- a/src/components/image/ImageZoomControls.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { useEffect, useRef } from 'react'; -import Viewer from 'viewerjs'; -import 'viewerjs/dist/viewer.css'; -import { clsx } from 'clsx/lite'; -import FullscreenButton from '../FullscreenButton'; - -export default function ImageZoomControls({ - children, - enableImageActions = false, - className, -}: { - children: React.ReactNode; - enableImageActions?: boolean; - className?: string; -}) { - const containerRef = useRef(null); - const viewerRef = useRef(null); - - useEffect(() => { - if (containerRef.current && enableImageActions) { - viewerRef.current = new Viewer(containerRef.current, { - inline: false, - button: true, - navbar: false, - title: false, - toolbar: { - zoomIn: 1, - zoomOut: 1, - reset: 1, - tooltip: 1, - }, - }); - return () => { - viewerRef.current?.destroy(); - }; - } - }, [enableImageActions]); - - return ( - <> - -
- {children} - {enableImageActions && ( - - )} -
- - ); -} diff --git a/src/components/image/useImageZoomControls.ts b/src/components/image/useImageZoomControls.ts new file mode 100644 index 00000000..324c639c --- /dev/null +++ b/src/components/image/useImageZoomControls.ts @@ -0,0 +1,29 @@ +import { RefObject, useEffect, useRef } from 'react'; +import Viewer from 'viewerjs'; + +export default function useImageZoomControls( + imageRef: RefObject, + isEnabled?: boolean, +) { + const viewerRef = useRef(null); + + useEffect(() => { + if (imageRef.current && isEnabled) { + viewerRef.current = new Viewer(imageRef.current, { + inline: false, + button: true, + navbar: false, + title: false, + toolbar: { + zoomIn: 1, + zoomOut: 1, + reset: 1, + tooltip: 1, + }, + }); + return () => { + viewerRef.current?.destroy(); + }; + } + }, [imageRef, isEnabled]); +} diff --git a/src/photo/PhotoDetailPage.tsx b/src/photo/PhotoDetailPage.tsx index f5bccfe7..49e8d8e7 100644 --- a/src/photo/PhotoDetailPage.tsx +++ b/src/photo/PhotoDetailPage.tsx @@ -113,7 +113,7 @@ export default function PhotoDetailPage({ shouldShareSimulation={simulation !== undefined} shouldScrollOnShare={false} includeFavoriteInAdminMenu={includeFavoriteInAdminMenu} - enableImageActions={ZOOM_CONTROLS_ENABLED} + shouldShowZoomControls={ZOOM_CONTROLS_ENABLED} />, ]} /> diff --git a/src/photo/PhotoLarge.tsx b/src/photo/PhotoLarge.tsx index eb7ad10e..b2ab48d3 100644 --- a/src/photo/PhotoLarge.tsx +++ b/src/photo/PhotoLarge.tsx @@ -36,7 +36,7 @@ import { useRef } from 'react'; import useOnVisible from '@/utility/useOnVisible'; import PhotoDate from './PhotoDate'; import { useAppState } from '@/state/AppState'; -import ImageZoomControls from '@/components/image/ImageZoomControls'; +import useImageZoomControls from '@/components/image/useImageZoomControls'; export default function PhotoLarge({ photo, @@ -55,9 +55,9 @@ export default function PhotoLarge({ shouldShareCamera, shouldShareSimulation, shouldShareFocalLength, + shouldShowZoomControls, includeFavoriteInAdminMenu, onVisible, - enableImageActions = false, }: { photo: Photo className?: string @@ -76,11 +76,12 @@ export default function PhotoLarge({ shouldShareSimulation?: boolean shouldShareFocalLength?: boolean shouldScrollOnShare?: boolean + shouldShowZoomControls?: boolean includeFavoriteInAdminMenu?: boolean onVisible?: () => void - enableImageActions?: boolean }) { const ref = useRef(null); + const refZoomControls = useRef(null); const tags = sortTags(photo.tags, primaryTag); @@ -92,6 +93,8 @@ export default function PhotoLarge({ useOnVisible(ref, onVisible); + useImageZoomControls(refZoomControls, shouldShowZoomControls); + const { arePhotosMatted, isUserSignedIn } = useAppState(); const hasTitle = @@ -146,14 +149,14 @@ export default function PhotoLarge({ arePhotosMatted && 'h-[90%]', arePhotosMatted && matteContentWidthForAspectRatio(), )}> - - + } contentSide={ diff --git a/src/site/viewerjs.css b/src/site/viewerjs.css new file mode 100644 index 00000000..e28f93cb --- /dev/null +++ b/src/site/viewerjs.css @@ -0,0 +1,16 @@ +@import 'viewerjs/dist/viewer.css'; + +.viewer-canvas { + background-color: black !important; +} +.viewer-reset::before { + content: '1:1'; + font-size: 13px; + font-weight: 600; + color: #fff; + display: inline-block; + position: relative; + bottom: -9px; + letter-spacing: -2px; + background-image: none; +}