Files
next-portfolio/src/app/photos/page.tsx
2024-04-25 20:18:27 +01:00

72 lines
2.0 KiB
TypeScript

import Image from "next/image";
import { glob } from "glob";
import sharp from 'sharp';
import exifReader from 'exif-reader';
import { pick } from 'radash';
import Lightbox from "@/components/lightbox";
type ImageData = {
width: number,
height: number,
blur: `data:image/${string}`,
src: string,
camera?: string,
exif: Partial<{
ExposureBiasValue: number,
FNumber: number,
ISOSpeedRatings: number,
FocalLength: number,
DateTimeOriginal: Date,
LensModel: string
}>
}
export async function getImages(): Promise<{images: ImageData[]}> {
const photosGlob = await glob(`public/photos/**/*.{png,jpeg,jpg}`, {
nodir: true,
});
const images = photosGlob.map(async (fileName) => {
const { width, height, exif } = await sharp(fileName).metadata();
const blur = await sharp(fileName)
.resize({ width: 12, height: 12, fit: 'inside' })
.toBuffer();
const exifData = exif ? exifReader(exif) : undefined;
return {
width: width ?? 10,
height: height ?? 10,
blur: `data:image/jpeg;base64,${blur.toString('base64')}` as `data:image/${string}`,
src: fileName.slice(6),
camera: exifData?.Image?.Model,
exif: pick(exifData?.Photo ?? {}, ['ExposureBiasValue', 'FNumber', 'ISOSpeedRatings', 'FocalLength', 'DateTimeOriginal', 'LensModel'])
};
});
return { images: await Promise.all(images) };
}
export default async function Home(): Promise<React.JSX.Element> {
const { images } = await getImages();
return (
<Lightbox imageData={images}>
{images.map((image) => (
<div className="relative" key={image.src}>
<Image
alt={image.src}
src={image.src}
className="object-contain h-auto w-full"
sizes="(min-width: 808px) 50vw, 100vw"
loading="lazy"
width={image.width}
height={image.height}
blurDataURL={image.blur}
placeholder={image.blur}
/>
</div>
))}
</Lightbox>
);
}