281 lines
8.2 KiB
JavaScript
281 lines
8.2 KiB
JavaScript
import React from "react";
|
|
import { graphql, navigate, Link } from "gatsby";
|
|
import {
|
|
getAspectRatio,
|
|
getMeta,
|
|
getName,
|
|
getShutterFractionFromExposureTime,
|
|
getVibrant,
|
|
getVibrantToHelmetSafeBodyStyle,
|
|
hasName,
|
|
} from "../../utils";
|
|
import { GatsbyImage, getImage } from "gatsby-plugin-image";
|
|
import { Helmet } from "react-helmet";
|
|
import classnames from "classnames";
|
|
import MetadataItem from "./MetadataItem";
|
|
|
|
const logKeyShortcut = (keyCode) => {
|
|
try {
|
|
// eslint-disable-next-line
|
|
window.plausible("KeyShortcut", { props: { keyCode } });
|
|
// eslint-disable-next-line
|
|
_paq.push(["trackEvent", "GalleryImage", "KeyShortcut", keyCode]);
|
|
} catch (e) {
|
|
/* do nothing */
|
|
}
|
|
};
|
|
|
|
const GalleryImage = ({ data, pageContext }) => {
|
|
const image = data.allFile.edges[0].node;
|
|
const ar = getAspectRatio(image);
|
|
|
|
React.useEffect(() => {
|
|
const keyListener = (e) => {
|
|
switch (e.code) {
|
|
case "ArrowRight": {
|
|
logKeyShortcut(e.code);
|
|
if (pageContext.nextImage) {
|
|
navigate(`/photogallery/${pageContext.nextImage}/`);
|
|
}
|
|
return;
|
|
}
|
|
case "ArrowLeft": {
|
|
logKeyShortcut(e.code);
|
|
if (pageContext.prevImage) {
|
|
navigate(`/photogallery/${pageContext.prevImage}/`);
|
|
}
|
|
return;
|
|
}
|
|
case "Escape":
|
|
case "KeyG": {
|
|
logKeyShortcut(e.code);
|
|
navigate("/photogallery/");
|
|
}
|
|
}
|
|
};
|
|
document.addEventListener("keydown", keyListener);
|
|
return () => {
|
|
document.removeEventListener("keydown", keyListener);
|
|
};
|
|
}, [pageContext]);
|
|
|
|
const name = getName(image);
|
|
const {meta, dateTaken: dt} = getMeta(image);
|
|
// const locationString = meta.City;
|
|
let locationString;
|
|
if (meta.City || meta.State || meta.Location) {
|
|
const location = [meta.Location, meta.City, meta.State].filter(
|
|
Boolean
|
|
);
|
|
locationString = location.join(", ");
|
|
}
|
|
const vibrant = getVibrant(image, true);
|
|
|
|
const orientationClasses =
|
|
ar > 1
|
|
? "flex-col mx-auto"
|
|
: "portrait:mx-auto landscape:mx-5 landscape:flex-row-reverse portrait:flex-col";
|
|
const shutterSpeed = React.useMemo(
|
|
() => getShutterFractionFromExposureTime(meta.ExposureTime || 0),
|
|
[meta]
|
|
);
|
|
const dateTaken = React.useMemo(() => new Date(dt), [dt]);
|
|
return (
|
|
<>
|
|
<Helmet>
|
|
<title>{name} - Gallery | Chuck Dries</title>
|
|
<body
|
|
className="text-vibrant-light bg-vibrant-dark"
|
|
style={getVibrantToHelmetSafeBodyStyle(vibrant)}
|
|
/>
|
|
</Helmet>
|
|
<div className="min-h-screen flex flex-col justify-between">
|
|
<nav className="mt-1 ml-1 text-lg mb-4">
|
|
<button
|
|
className="hover:underline text-vibrant-light hover:text-muted-light arrow-left-before mr-1"
|
|
onClick={() => navigate(-1)}
|
|
type="button"
|
|
>
|
|
back
|
|
</button>
|
|
<Link
|
|
className="hover:underline text-vibrant-light hover:text-muted-light mx-1"
|
|
to="/"
|
|
>
|
|
home
|
|
</Link>
|
|
<Link
|
|
className="hover:underline text-vibrant-light hover:text-muted-light mx-1"
|
|
to="/photogallery/"
|
|
>
|
|
gallery <span className="bg-gray-300 text-black">esc</span>
|
|
</Link>
|
|
{pageContext.prevImage && (
|
|
<Link
|
|
className="hover:underline text-vibrant-light hover:text-muted-light mx-1"
|
|
to={`/photogallery/${pageContext.prevImage}/`}
|
|
>
|
|
previous <span className="bg-gray-300 text-black">⭠</span>
|
|
</Link>
|
|
)}
|
|
{pageContext.nextImage && (
|
|
<Link
|
|
className="hover:underline text-vibrant-light hover:text-muted-light mx-1"
|
|
to={`/photogallery/${pageContext.nextImage}/`}
|
|
>
|
|
next <span className="bg-gray-300 text-black">⭢</span>
|
|
</Link>
|
|
)}
|
|
</nav>
|
|
<div className={classnames("flex", orientationClasses)}>
|
|
<div className="flex-grow-0">
|
|
<GatsbyImage
|
|
alt={name}
|
|
className=""
|
|
image={getImage(image)}
|
|
key={image.base}
|
|
loading="eager"
|
|
objectFit="contain"
|
|
style={{
|
|
maxWidth: `calc(max(90vh, 500px) * ${ar})`,
|
|
maxHeight: "90vh",
|
|
// minHeight: '500px',
|
|
}}
|
|
/>
|
|
</div>
|
|
<div
|
|
className={classnames(
|
|
"px-2 flex flex-row portrait:items-end mx-auto",
|
|
ar <= 1
|
|
? "pt-5 flex-col flex-auto text-right"
|
|
: "container portrait:pt-5 portrait:flex-col portrait:text-right"
|
|
)}
|
|
>
|
|
<div className="flex-auto mr-2">
|
|
<p className="text-muted-light font-mono text-sm m-0 mt-1">
|
|
{image.base}
|
|
</p>
|
|
{hasName(image) && (
|
|
<h1 className="text-4xl mt-0 font-serif">{name}</h1>
|
|
)}
|
|
<p className="landscape:mr-2">{meta.Caption}</p>
|
|
</div>
|
|
{
|
|
<div
|
|
className="portrait:border-t-2 border-muted-light portrait:mt-2 mr-2 portrait:mb-1"
|
|
style={{ width: 30 }}
|
|
></div>
|
|
}
|
|
<div className='flex flex-col'>
|
|
<MetadataItem
|
|
data={dateTaken.toLocaleDateString()}
|
|
icon="calendar-outline"
|
|
title="date taken"
|
|
/>
|
|
<MetadataItem
|
|
data={locationString}
|
|
icon="map-outline"
|
|
title="location"
|
|
/>
|
|
{(meta.Make || meta.Model) && (
|
|
<MetadataItem
|
|
data={[meta.Make, meta.Model].join(" ")}
|
|
icon="camera-outline"
|
|
title="camera"
|
|
/>
|
|
)}
|
|
{(meta.LensModel || meta.FocalLength) && (
|
|
<MetadataItem
|
|
data={[
|
|
meta.LensModel === "----" ? null : meta.LensModel,
|
|
meta.FocalLength && `${meta.FocalLength}mm`,
|
|
]
|
|
.filter(Boolean)
|
|
.join(" @")}
|
|
icon="ellipse"
|
|
title="lens"
|
|
/>
|
|
)}
|
|
<MetadataItem
|
|
data={shutterSpeed}
|
|
icon="stopwatch-outline"
|
|
title="shutter speed"
|
|
/>
|
|
{meta.FNumber && (
|
|
<MetadataItem
|
|
data={`f/${meta.FNumber}`}
|
|
icon="aperture-outline"
|
|
title="aperture"
|
|
/>
|
|
)}
|
|
<MetadataItem
|
|
data={meta.ISO}
|
|
icon="film-outline"
|
|
title="ISO"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div></div>
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const query = graphql`
|
|
query GalleryImage($imageFilename: String) {
|
|
allFile(
|
|
filter: {
|
|
sourceInstanceName: { eq: "gallery" }
|
|
base: { eq: $imageFilename }
|
|
}
|
|
) {
|
|
edges {
|
|
node {
|
|
base
|
|
childImageSharp {
|
|
fluid {
|
|
aspectRatio
|
|
}
|
|
gatsbyImageData(
|
|
layout: CONSTRAINED
|
|
# placeholder: BLURRED
|
|
placeholder: DOMINANT_COLOR
|
|
# placeholder: TRACED_SVG
|
|
height: 2160
|
|
)
|
|
}
|
|
fields {
|
|
imageMeta {
|
|
dateTaken
|
|
meta {
|
|
Make
|
|
Model
|
|
ExposureTime
|
|
FNumber
|
|
ISO
|
|
DateTimeOriginal
|
|
CreateDate
|
|
ShutterSpeedValue
|
|
ApertureValue
|
|
FocalLength
|
|
LensModel
|
|
ObjectName
|
|
Caption
|
|
Location
|
|
City
|
|
State
|
|
}
|
|
vibrant {
|
|
...VibrantColors
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
export default GalleryImage;
|