Switch to YARL
This commit is contained in:
15
package-lock.json
generated
15
package-lock.json
generated
@@ -33,7 +33,8 @@
|
|||||||
"sharp": "^0.33.3",
|
"sharp": "^0.33.3",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5",
|
||||||
|
"yet-another-react-lightbox": "^3.17.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@aashutoshrathi/word-wrap": {
|
"node_modules/@aashutoshrathi/word-wrap": {
|
||||||
@@ -6397,6 +6398,18 @@
|
|||||||
"node": ">= 14"
|
"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": {
|
"node_modules/yocto-queue": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"sharp": "^0.33.3",
|
"sharp": "^0.33.3",
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5",
|
||||||
|
"yet-another-react-lightbox": "^3.17.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Image from "next/image";
|
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 = {
|
type ImageData = {
|
||||||
width: number,
|
width: number,
|
||||||
@@ -24,53 +37,77 @@ type LightboxProps = {
|
|||||||
imageData: ImageData[]
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="grid gap-2 grid-cols-3">
|
<div className="grid gap-2 grid-cols-3">
|
||||||
{props.children.map((image, index) => (
|
{props.children.map((image, index) => (
|
||||||
<button key={`lightbox_img_${index}`} onClick={(() => {
|
<button key={`lightbox_img_${index}`} onClick={(() => {
|
||||||
setActive(props.imageData[index]);
|
setActive(index);
|
||||||
})}>
|
})}>
|
||||||
{image}
|
{image}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{ active ? (
|
<YARL
|
||||||
<div className="fixed top-0 left-0 w-full h-full z-30">
|
open={!!active}
|
||||||
<div className="bg-black bg-opacity-80 w-full h-full p-12">
|
close={() => setActive(null)}
|
||||||
<div className="flex flex-col w-full h-full">
|
index={active ?? undefined}
|
||||||
<div className="p-1 mb-4">
|
slides={props.imageData}
|
||||||
<span className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple">{active.exif.DateTimeOriginal?.toLocaleDateString()}</span>
|
// @ts-expect-error - Todo - This just passes the slide through, but it doesn't know the type
|
||||||
<button className="text-white py-1.5 px-3 bg-dracula-bg-lighter border border-dracula-purple" onClick={() => setActive(null)}>
|
render={{ slide: (args) => NextJsImage({...args, unoptimized: true }), thumbnail: NextJsImage }}
|
||||||
<span>x</span>
|
plugins={[Thumbnails, Zoom, Captions]}
|
||||||
</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}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user