Switch to YARL

This commit is contained in:
2024-05-12 20:03:12 +01:00
parent 6343dda1fa
commit 433ba19a7a
3 changed files with 92 additions and 41 deletions

15
package-lock.json generated
View File

@@ -33,7 +33,8 @@
"sharp": "^0.33.3",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"yet-another-react-lightbox": "^3.17.4"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -6397,6 +6398,18 @@
"node": ">= 14"
}
},
"node_modules/yet-another-react-lightbox": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/yet-another-react-lightbox/-/yet-another-react-lightbox-3.17.4.tgz",
"integrity": "sha512-XDCZoEXsjkbRy7Pxk+nsQthbYqW7V2INHv9Qn9GmdILP4GH7wANsRF31TCXIKMU4etr3UHmPzClLXf7KpIwDYQ==",
"engines": {
"node": ">=14"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@@ -36,6 +36,7 @@
"sharp": "^0.33.3",
"tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"yet-another-react-lightbox": "^3.17.4"
}
}

View File

@@ -1,7 +1,20 @@
"use client";
import { useState } from "react";
import React, { useState } from "react";
import Image from "next/image";
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
import YARL, {
isImageFitCover,
isImageSlide,
useLightboxProps,
useLightboxState,
} from "yet-another-react-lightbox";
import Thumbnails from "yet-another-react-lightbox/plugins/thumbnails";
import Zoom from "yet-another-react-lightbox/plugins/zoom";
import Captions from "yet-another-react-lightbox/plugins/captions";
import "yet-another-react-lightbox/styles.css";
import "yet-another-react-lightbox/plugins/thumbnails.css";
import "yet-another-react-lightbox/plugins/captions.css";
type ImageData = {
width: number,
@@ -24,53 +37,77 @@ type LightboxProps = {
imageData: ImageData[]
}
export default function Lightbox(props: LightboxProps): React.JSX.Element {
const [active, setActive] = useState<ImageData | null>(null);
function NextJsImage({ slide, offset, rect, unoptimized = false }: {slide: ImageData, offset: number, rect: {width: number, height: number}, unoptimized: boolean}): React.JSX.Element {
const {
on: { click },
carousel: { imageFit },
} = useLightboxProps();
const { currentIndex } = useLightboxState();
const cover = isImageSlide(slide) && isImageFitCover(slide, imageFit);
const width = !cover
? Math.round(
Math.min(rect.width, (rect.height / slide.height) * slide.width),
)
: rect.width;
const height = !cover
? Math.round(
Math.min(rect.height, (rect.width / slide.width) * slide.height),
)
: rect.height;
console.log(slide);
return (
<div style={{ position: "relative", width, height }}>
<Image
fill
alt=""
src={slide}
loading="eager"
unoptimized={unoptimized}
draggable={false}
blurDataURL={slide.blur}
placeholder={slide.blur}
style={{
objectFit: cover ? "cover" : "contain",
cursor: click ? "pointer" : undefined,
}}
sizes={`${Math.ceil((width / window.innerWidth) * 100)}vw`}
onClick={
offset === 0 ? (): void => click?.({ index: currentIndex }) : undefined
}
/>
</div>
);
}
export default function MyLightbox(props: LightboxProps): React.JSX.Element {
const [active, setActive] = useState<number | null>(null);
return (
<>
<div className="grid gap-2 grid-cols-3">
{props.children.map((image, index) => (
<button key={`lightbox_img_${index}`} onClick={(() => {
setActive(props.imageData[index]);
setActive(index);
})}>
{image}
</button>
))}
</div>
{ active ? (
<div className="fixed top-0 left-0 w-full h-full z-30">
<div className="bg-black bg-opacity-80 w-full h-full p-12">
<div className="flex flex-col w-full h-full">
<div className="p-1 mb-4">
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.exif.DateTimeOriginal?.toLocaleDateString()}</span>
<button className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple" onClick={() => setActive(null)}>
<span>x</span>
</button>
</div>
<div className="relative w-full h-full m-auto">
<Image
alt={active.src}
src={active.src}
className="opacity-100 object-contain m-auto"
loading="eager"
unoptimized={true}
fill
blurDataURL={active.blur}
placeholder={active.blur}
/>
</div>
<div className="flex flex-row flex-wrap self-center justify-center gap-4 max-w-3xl mt-4">
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.camera}</span>
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.exif.LensModel}</span>
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.exif.FocalLength}mm</span>
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">f/{active.exif.FNumber}</span>
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">ISO {active.exif.ISOSpeedRatings}</span>
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.exif.ExposureBiasValue}EV</span>
</div>
</div>
</div>
</div>
) : null}
<YARL
open={!!active}
close={() => setActive(null)}
index={active ?? undefined}
slides={props.imageData}
// @ts-expect-error - Todo - This just passes the slide through, but it doesn't know the type
render={{ slide: (args) => NextJsImage({...args, unoptimized: true }), thumbnail: NextJsImage }}
plugins={[Thumbnails, Zoom, Captions]}
/>
</>
);
}