Merge branch 'remove-dynamic-colors' into main
This commit is contained in:
commit
7ffb2e31c1
@ -40,41 +40,41 @@ function processColors(vibrantData: Palette, imagePath: string) {
|
|||||||
let DarkMuted = chroma(vibrantData.DarkMuted!.getRgb());
|
let DarkMuted = chroma(vibrantData.DarkMuted!.getRgb());
|
||||||
let LightMuted = chroma(vibrantData.LightMuted!.getRgb());
|
let LightMuted = chroma(vibrantData.LightMuted!.getRgb());
|
||||||
|
|
||||||
// first pass - darken bg and lighten relevant fg colors
|
// // first pass - darken bg and lighten relevant fg colors
|
||||||
if (
|
// if (
|
||||||
badContrast(DarkVibrant, Vibrant) ||
|
// badContrast(DarkVibrant, Vibrant) ||
|
||||||
badContrast(DarkVibrant, LightMuted)
|
// badContrast(DarkVibrant, LightMuted)
|
||||||
) {
|
// ) {
|
||||||
DarkVibrant = DarkVibrant.darken();
|
// DarkVibrant = DarkVibrant.darken();
|
||||||
}
|
// }
|
||||||
if (badContrast(DarkVibrant, Vibrant)) {
|
// if (badContrast(DarkVibrant, Vibrant)) {
|
||||||
Vibrant = Vibrant.brighten();
|
// Vibrant = Vibrant.brighten();
|
||||||
}
|
// }
|
||||||
if (badContrast(DarkVibrant, Vibrant)) {
|
// if (badContrast(DarkVibrant, Vibrant)) {
|
||||||
Vibrant = Vibrant.brighten();
|
// Vibrant = Vibrant.brighten();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// second pass - first doesn't always do enough
|
// // second pass - first doesn't always do enough
|
||||||
if (badContrast(DarkVibrant, Vibrant)) {
|
// if (badContrast(DarkVibrant, Vibrant)) {
|
||||||
Vibrant = Vibrant.brighten(2);
|
// Vibrant = Vibrant.brighten(2);
|
||||||
}
|
// }
|
||||||
if (badContrast(DarkVibrant, LightMuted)) {
|
// if (badContrast(DarkVibrant, LightMuted)) {
|
||||||
LightMuted = LightMuted.brighten(2);
|
// LightMuted = LightMuted.brighten(2);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// only used for hover styles, so we should give it a shot but it's not a huge deal if it's not very legible
|
// // only used for hover styles, so we should give it a shot but it's not a huge deal if it's not very legible
|
||||||
if (badContrast(Muted, LightMuted)) {
|
// if (badContrast(Muted, LightMuted)) {
|
||||||
Muted = Muted.darken();
|
// Muted = Muted.darken();
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (badContrast(DarkVibrant, Vibrant)) {
|
// if (badContrast(DarkVibrant, Vibrant)) {
|
||||||
console.warn("contrast still too low", imagePath);
|
// console.warn("contrast still too low", imagePath);
|
||||||
logColorsWithContrast(Vibrant, DarkVibrant, "V-DV");
|
// logColorsWithContrast(Vibrant, DarkVibrant, "V-DV");
|
||||||
}
|
// }
|
||||||
if (badContrast(DarkVibrant, LightMuted)) {
|
// if (badContrast(DarkVibrant, LightMuted)) {
|
||||||
console.warn("contrast still too low", imagePath);
|
// console.warn("contrast still too low", imagePath);
|
||||||
logColorsWithContrast(LightMuted, DarkVibrant, "LM-DV");
|
// logColorsWithContrast(LightMuted, DarkVibrant, "LM-DV");
|
||||||
}
|
// }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Vibrant: Vibrant.rgb(),
|
Vibrant: Vibrant.rgb(),
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
"react-cool-dimensions": "^2.0.7",
|
"react-cool-dimensions": "^2.0.7",
|
||||||
"react-div-100vh": "^0.7.0",
|
"react-div-100vh": "^0.7.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "latest",
|
||||||
"react-stately": "^3.19.0",
|
"react-stately": "^3.19.0",
|
||||||
"react-tiny-popover": "^7.2.0",
|
"react-tiny-popover": "^7.2.0",
|
||||||
"sass": "^1.34.0",
|
"sass": "^1.34.0",
|
||||||
|
@ -3,6 +3,7 @@ import { graphql, navigate, Link } from "gatsby";
|
|||||||
import { GatsbyImage, getImage } from "gatsby-plugin-image";
|
import { GatsbyImage, getImage } from "gatsby-plugin-image";
|
||||||
import { Helmet } from "react-helmet";
|
import { Helmet } from "react-helmet";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
|
import chroma, { Color } from "chroma-js";
|
||||||
|
|
||||||
import ChevronLeft from "@spectrum-icons/workflow/ChevronLeft";
|
import ChevronLeft from "@spectrum-icons/workflow/ChevronLeft";
|
||||||
import ChevronRight from "@spectrum-icons/workflow/ChevronRight";
|
import ChevronRight from "@spectrum-icons/workflow/ChevronRight";
|
||||||
@ -25,6 +26,7 @@ import {
|
|||||||
hasName,
|
hasName,
|
||||||
getCanonicalSize,
|
getCanonicalSize,
|
||||||
getGalleryPageUrl,
|
getGalleryPageUrl,
|
||||||
|
getVibrantStyle,
|
||||||
} from "../../utils";
|
} from "../../utils";
|
||||||
import MetadataItem from "./MetadataItem";
|
import MetadataItem from "./MetadataItem";
|
||||||
import Nav from "../Nav";
|
import Nav from "../Nav";
|
||||||
@ -41,11 +43,11 @@ const logKeyShortcut = (keyCode) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const IconStyle = {
|
const IconStyle = {
|
||||||
width: '24px',
|
width: "24px",
|
||||||
margin: '0 4px'
|
margin: "0 4px",
|
||||||
}
|
};
|
||||||
|
|
||||||
const ArrowLinkClasses = `hover:underline text-vibrant-light hover:text-muted-light
|
const ArrowLinkClasses = `hover:underline text-black
|
||||||
lg:px-4 self-stretch flex items-center hover:bg-black/50 max-h-screen sticky top-0
|
lg:px-4 self-stretch flex items-center hover:bg-black/50 max-h-screen sticky top-0
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -133,6 +135,10 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
locationString = location.join(", ");
|
locationString = location.join(", ");
|
||||||
}
|
}
|
||||||
const vibrant = getVibrant(image, true);
|
const vibrant = getVibrant(image, true);
|
||||||
|
const BLEND = 'hsl'
|
||||||
|
const darkAccent = chroma
|
||||||
|
.mix(vibrant.Vibrant, "hsla(216, 0%, 90%, 1)", 0.6, BLEND)
|
||||||
|
.hex();
|
||||||
const canonicalSize = getCanonicalSize(image);
|
const canonicalSize = getCanonicalSize(image);
|
||||||
|
|
||||||
const orientationClasses =
|
const orientationClasses =
|
||||||
@ -142,7 +148,10 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
const verticalPad = ar > 1 ? "250px" : "100px";
|
const verticalPad = ar > 1 ? "250px" : "100px";
|
||||||
|
|
||||||
const shutterSpeed = React.useMemo(
|
const shutterSpeed = React.useMemo(
|
||||||
() => meta.ExposureTime ? getShutterFractionFromExposureTime(meta.ExposureTime) : null,
|
() =>
|
||||||
|
meta.ExposureTime
|
||||||
|
? getShutterFractionFromExposureTime(meta.ExposureTime)
|
||||||
|
: null,
|
||||||
[meta]
|
[meta]
|
||||||
);
|
);
|
||||||
const dateTaken = React.useMemo(() => new Date(dt), [dt]);
|
const dateTaken = React.useMemo(() => new Date(dt), [dt]);
|
||||||
@ -151,8 +160,11 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{name} - Gallery | Chuck Dries</title>
|
<title>{name} - Gallery | Chuck Dries</title>
|
||||||
<body
|
<body
|
||||||
className="text-vibrant-light bg-vibrant-dark transition-colors"
|
className="text-black transition-colors"
|
||||||
style={getHelmetSafeBodyStyle(vibrant)}
|
// style={getHelmetSafeBodyStyle(vibrant)}
|
||||||
|
style={getHelmetSafeBodyStyle({
|
||||||
|
background: chroma.mix(vibrant.Vibrant, "white", 0.7, BLEND).hex(),
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<div className="min-h-screen flex flex-col justify-between overflow-x-hidden">
|
<div className="min-h-screen flex flex-col justify-between overflow-x-hidden">
|
||||||
@ -167,7 +179,13 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
),
|
),
|
||||||
label: (
|
label: (
|
||||||
<>
|
<>
|
||||||
Gallery <kbd className="font-normal">esc</kbd>
|
Gallery{" "}
|
||||||
|
<kbd
|
||||||
|
className="font-normal"
|
||||||
|
style={{ background: darkAccent }}
|
||||||
|
>
|
||||||
|
esc
|
||||||
|
</kbd>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -186,7 +204,12 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
}}
|
}}
|
||||||
to={`/photogallery/${prevImage}/`}
|
to={`/photogallery/${prevImage}/`}
|
||||||
>
|
>
|
||||||
<span className="p-1 lg:p-4 bg-muted-light/25 rounded-full">
|
<span
|
||||||
|
className="p-1 lg:p-4 rounded-full"
|
||||||
|
style={{
|
||||||
|
background: darkAccent,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ChevronLeft UNSAFE_style={IconStyle} />
|
<ChevronLeft UNSAFE_style={IconStyle} />
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
@ -216,7 +239,7 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
) : (
|
) : (
|
||||||
<GatsbyImage
|
<GatsbyImage
|
||||||
alt={name}
|
alt={name}
|
||||||
className="border-4 border-vibrant"
|
className="border-4 border-black"
|
||||||
image={getImage(image)}
|
image={getImage(image)}
|
||||||
key={image.base}
|
key={image.base}
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@ -232,39 +255,68 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
: "flex-row landscape:container portrait:pt-5 portrait:flex-col portrait:text-right portrait:items-end"
|
: "flex-row landscape:container portrait:pt-5 portrait:flex-col portrait:text-right portrait:items-end"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="mr-2">
|
<div className="mr-2 flex flex-col">
|
||||||
<p className="text-muted-light font-mono text-sm m-0 mt-1">
|
<p className="font-mono text-sm m-0 mt-1">{image.base}</p>
|
||||||
{image.base}
|
|
||||||
</p>
|
|
||||||
{hasName(image) && (
|
{hasName(image) && (
|
||||||
<h1 className="text-4xl mt-0 font-sans">{name}</h1>
|
<h1 className="text-4xl mt-0 font-sans">{name}</h1>
|
||||||
)}
|
)}
|
||||||
<p className="landscape:mr-2">{meta.Caption}</p>
|
<p className="landscape:mr-2">{meta.Caption}</p>
|
||||||
<a
|
<div
|
||||||
className="cursor-pointer inline-block bg-muted-light text-vibrant-dark font-sans p-1 my-1 rounded"
|
className={classnames(
|
||||||
download
|
"grid grid-cols-6 h-[40px] w-[240px]",
|
||||||
href={image.publicURL}
|
ar <= 1 ? "self-end" : "portrait:self-end"
|
||||||
onClick={() => {
|
)}
|
||||||
try {
|
|
||||||
window.plausible("Download Wallpaper", {
|
|
||||||
props: { image: image.base },
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Download wallpaper
|
<div
|
||||||
</a>
|
style={{ background: `rgba(${vibrant.Vibrant.join(",")})` }}
|
||||||
<div className="grid grid-cols-6 w-full h-[30px]">
|
></div>
|
||||||
<div className="bg-vibrant"></div>
|
<div
|
||||||
<div className="bg-vibrant-light"></div>
|
style={{
|
||||||
<div className="bg-vibrant-dark"></div>
|
background: `rgb(${vibrant.LightVibrant.join(",")})`,
|
||||||
<div className="bg-muted"></div>
|
}}
|
||||||
<div className="bg-muted-light"></div>
|
></div>
|
||||||
<div className="bg-muted-dark"></div>
|
<div
|
||||||
|
style={{
|
||||||
|
background: `rgb(${vibrant.DarkVibrant.join(",")})`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
style={{ background: `rgb(${vibrant.Muted.join(",")})` }}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: `rgb(${vibrant.LightMuted.join(",")})`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: `rgb(${vibrant.DarkMuted.join(",")})`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div><div className="flex-auto"></div>
|
<div className="my-2">
|
||||||
|
<a
|
||||||
|
className="cursor-pointer text-black font-sans p-1 rounded"
|
||||||
|
download
|
||||||
|
href={image.publicURL}
|
||||||
|
onClick={() => {
|
||||||
|
try {
|
||||||
|
window.plausible("Download Wallpaper", {
|
||||||
|
props: { image: image.base },
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
background: darkAccent,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Download wallpaper
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex-auto"></div>
|
||||||
{
|
{
|
||||||
<div
|
<div
|
||||||
className="portrait:border-t-2 border-muted-light portrait:mt-2 mr-2 portrait:mb-1"
|
className="portrait:border-t-2 border-muted-light portrait:mt-2 mr-2 portrait:mb-1"
|
||||||
@ -277,7 +329,7 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
icon={<Calendar UNSAFE_style={IconStyle} />}
|
icon={<Calendar UNSAFE_style={IconStyle} />}
|
||||||
title="date taken"
|
title="date taken"
|
||||||
/>
|
/>
|
||||||
<div className="sm:flex justify-end gap-2 border border-vibrant-light pl-2 rounded">
|
<div className="sm:flex justify-end gap-2 border border-gray-500 pl-2 rounded">
|
||||||
<MetadataItem
|
<MetadataItem
|
||||||
data={shutterSpeed}
|
data={shutterSpeed}
|
||||||
icon={<Stopwatch UNSAFE_style={IconStyle} />}
|
icon={<Stopwatch UNSAFE_style={IconStyle} />}
|
||||||
@ -315,7 +367,7 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
)}
|
)}
|
||||||
{(meta.LensModel || meta.FocalLength) && (
|
{(meta.LensModel || meta.FocalLength) && (
|
||||||
<MetadataItem
|
<MetadataItem
|
||||||
data={ meta.LensModel === "----" ? null : meta.LensModel}
|
data={meta.LensModel === "----" ? null : meta.LensModel}
|
||||||
icon={<Circle UNSAFE_style={IconStyle} />}
|
icon={<Circle UNSAFE_style={IconStyle} />}
|
||||||
title="lens"
|
title="lens"
|
||||||
/>
|
/>
|
||||||
@ -334,7 +386,12 @@ const GalleryImage = ({ data, location: { state } }) => {
|
|||||||
}}
|
}}
|
||||||
to={`/photogallery/${nextImage}/`}
|
to={`/photogallery/${nextImage}/`}
|
||||||
>
|
>
|
||||||
<span className="p-1 lg:p-4 bg-muted-light/25 rounded-full">
|
<span
|
||||||
|
className="p-1 lg:p-4 rounded-full"
|
||||||
|
style={{
|
||||||
|
background: darkAccent,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ChevronRight UNSAFE_style={IconStyle} />
|
<ChevronRight UNSAFE_style={IconStyle} />
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -25,6 +25,7 @@ interface MasonryGalleryProps {
|
|||||||
debugHue?: boolean;
|
debugHue?: boolean;
|
||||||
debugRating?: boolean;
|
debugRating?: boolean;
|
||||||
linkState?: object;
|
linkState?: object;
|
||||||
|
showPalette?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MasonryGallery = ({
|
const MasonryGallery = ({
|
||||||
@ -33,6 +34,7 @@ const MasonryGallery = ({
|
|||||||
debugHue,
|
debugHue,
|
||||||
debugRating,
|
debugRating,
|
||||||
linkState,
|
linkState,
|
||||||
|
showPalette,
|
||||||
}: MasonryGalleryProps) => {
|
}: MasonryGalleryProps) => {
|
||||||
const [isClient, setIsClient] = React.useState(false);
|
const [isClient, setIsClient] = React.useState(false);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@ -124,7 +126,7 @@ const MasonryGallery = ({
|
|||||||
const rowAspectRatioSum = currentRow.aspect;
|
const rowAspectRatioSum = currentRow.aspect;
|
||||||
const ar = getAspectRatio(image);
|
const ar = getAspectRatio(image);
|
||||||
let width;
|
let width;
|
||||||
let height = `calc(${galleryWidth} / ${rowAspectRatioSum} + 10px)`;
|
let height = `calc(${galleryWidth} / ${rowAspectRatioSum} ${showPalette ? "+ 10px" : "- 10px"})`;
|
||||||
if (rowAspectRatioSum < targetAspect * 0.66) {
|
if (rowAspectRatioSum < targetAspect * 0.66) {
|
||||||
// incomplete row, render stuff at "ideal" sizes instead of filling width
|
// incomplete row, render stuff at "ideal" sizes instead of filling width
|
||||||
width = `calc(calc(100vw - 160px) / ${targetAspect / ar})`;
|
width = `calc(calc(100vw - 160px) / ${targetAspect / ar})`;
|
||||||
@ -137,9 +139,7 @@ const MasonryGallery = ({
|
|||||||
const img = getImage(image);
|
const img = getImage(image);
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
className={classNames(
|
className={classNames("border-8 border-white overflow-hidden")}
|
||||||
"border-8 border-white overflow-hidden"
|
|
||||||
)}
|
|
||||||
id={image.base}
|
id={image.base}
|
||||||
key={`${image.base}`}
|
key={`${image.base}`}
|
||||||
state={{
|
state={{
|
||||||
@ -166,13 +166,22 @@ const MasonryGallery = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{img && (
|
{img && (
|
||||||
|
<div className={`h-full ${showPalette && "grid grid-rows-[1fr_20px]"}`}>
|
||||||
<GatsbyImage
|
<GatsbyImage
|
||||||
alt={getName(image)}
|
alt={getName(image)}
|
||||||
className="w-full h-full"
|
className="w-full"
|
||||||
image={img}
|
image={img}
|
||||||
objectFit="cover"
|
objectFit="cover"
|
||||||
/>
|
/>
|
||||||
|
{ showPalette && <div className="grid grid-cols-6 flex-shrink-0 h-[20px] w-full" style={getVibrantStyle(getVibrant(image))}>
|
||||||
|
<div className="bg-vibrant"></div>
|
||||||
|
<div className="bg-vibrant-light"></div>
|
||||||
|
<div className="bg-vibrant-dark"></div>
|
||||||
|
<div className="bg-muted"></div>
|
||||||
|
<div className="bg-muted-light"></div>
|
||||||
|
<div className="bg-muted-dark"></div>
|
||||||
|
</div>}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ import { Link } from "gatsby";
|
|||||||
import { Popover } from "react-tiny-popover";
|
import { Popover } from "react-tiny-popover";
|
||||||
|
|
||||||
const navClasses =
|
const navClasses =
|
||||||
"hover:underline hover:bg-transparentblack block p-3 text-vibrant-light";
|
"hover:underline hover:bg-transparentblack block p-3 text-black";
|
||||||
|
|
||||||
const ExternalLinks = () => (
|
const ExternalLinks = () => (
|
||||||
<ul
|
<ul
|
||||||
|
60
src/components/Switch.tsx
Normal file
60
src/components/Switch.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { useToggleState } from "react-stately";
|
||||||
|
import {
|
||||||
|
AriaSwitchProps,
|
||||||
|
useFocusRing,
|
||||||
|
useSwitch,
|
||||||
|
VisuallyHidden,
|
||||||
|
} from "react-aria";
|
||||||
|
|
||||||
|
export function Switch(props: AriaSwitchProps) {
|
||||||
|
let state = useToggleState(props);
|
||||||
|
let ref = React.useRef<HTMLInputElement>(null);
|
||||||
|
let { inputProps } = useSwitch(props, state, ref);
|
||||||
|
let { isFocusVisible, focusProps } = useFocusRing();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
className="text-sm p-2"
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
opacity: props.isDisabled ? 0.4 : 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VisuallyHidden>
|
||||||
|
<input {...inputProps} {...focusProps} ref={ref} />
|
||||||
|
</VisuallyHidden>
|
||||||
|
<svg
|
||||||
|
className="flex-shrink-0"
|
||||||
|
width={40}
|
||||||
|
height={24}
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{ marginRight: 4 }}
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
x={4}
|
||||||
|
y={4}
|
||||||
|
width={32}
|
||||||
|
height={16}
|
||||||
|
rx={8}
|
||||||
|
fill={state.isSelected ? "orange" : "gray"}
|
||||||
|
/>
|
||||||
|
<circle cx={state.isSelected ? 28 : 12} cy={12} r={5} fill="white" />
|
||||||
|
{isFocusVisible && (
|
||||||
|
<rect
|
||||||
|
x={1}
|
||||||
|
y={1}
|
||||||
|
width={38}
|
||||||
|
height={22}
|
||||||
|
rx={11}
|
||||||
|
fill="none"
|
||||||
|
stroke="orange"
|
||||||
|
strokeWidth={2}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
{props.children}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
2
src/gatsby-types.d.ts
vendored
2
src/gatsby-types.d.ts
vendored
@ -2550,7 +2550,7 @@ type GalleryImageQuery = { readonly file: { readonly base: string, readonly publ
|
|||||||
type GalleryPageQueryQueryVariables = Exact<{ [key: string]: never; }>;
|
type GalleryPageQueryQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
type GalleryPageQueryQuery = { readonly allFile: { readonly nodes: ReadonlyArray<{ readonly relativePath: string, readonly base: string, readonly childImageSharp: { readonly gatsbyImageData: import('gatsby-plugin-image').IGatsbyImageData, readonly fluid: { readonly aspectRatio: number } | null } | null, readonly fields: { readonly imageMeta: { readonly vibrantHue: number | null, readonly dominantHue: ReadonlyArray<number | null> | null, readonly dateTaken: string | null, readonly meta: { readonly Keywords: ReadonlyArray<string | null> | null, readonly Rating: number | null, readonly ObjectName: string | null } | null, readonly vibrant: { readonly Vibrant: ReadonlyArray<number | null> | null } | null } | null } | null }> } };
|
type GalleryPageQueryQuery = { readonly allFile: { readonly nodes: ReadonlyArray<{ readonly relativePath: string, readonly base: string, readonly childImageSharp: { readonly gatsbyImageData: import('gatsby-plugin-image').IGatsbyImageData, readonly fluid: { readonly aspectRatio: number } | null } | null, readonly fields: { readonly imageMeta: { readonly vibrantHue: number | null, readonly dominantHue: ReadonlyArray<number | null> | null, readonly dateTaken: string | null, readonly meta: { readonly Keywords: ReadonlyArray<string | null> | null, readonly Rating: number | null, readonly ObjectName: string | null } | null, readonly vibrant: { readonly DarkMuted: ReadonlyArray<number | null> | null, readonly DarkVibrant: ReadonlyArray<number | null> | null, readonly LightMuted: ReadonlyArray<number | null> | null, readonly LightVibrant: ReadonlyArray<number | null> | null, readonly Vibrant: ReadonlyArray<number | null> | null, readonly Muted: ReadonlyArray<number | null> | null } | null } | null } | null }> } };
|
||||||
|
|
||||||
type GatsbyImageSharpFixedFragment = { readonly base64: string | null, readonly width: number, readonly height: number, readonly src: string, readonly srcSet: string };
|
type GatsbyImageSharpFixedFragment = { readonly base64: string | null, readonly width: number, readonly height: number, readonly src: string, readonly srcSet: string };
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { Helmet } from "react-helmet";
|
|||||||
// import { take } from "ramda";
|
// import { take } from "ramda";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
|
|
||||||
import { getHelmetSafeBodyStyle, getAspectRatio } from "../utils";
|
import { getHelmetSafeBodyStyle, getAspectRatio, getVibrantStyle } from "../utils";
|
||||||
import Nav from "../components/Nav";
|
import Nav from "../components/Nav";
|
||||||
// import ActionButtons from "../components/index/ActionButtons";
|
// import ActionButtons from "../components/index/ActionButtons";
|
||||||
import { use100vh } from "react-div-100vh";
|
import { use100vh } from "react-div-100vh";
|
||||||
@ -73,14 +73,14 @@ const IndexPage = ({
|
|||||||
<body
|
<body
|
||||||
className="bg-white transition-colors"
|
className="bg-white transition-colors"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
style={getHelmetSafeBodyStyle({
|
style={getHelmetSafeBodyStyle(getVibrantStyle({
|
||||||
Muted: [0, 0, 0],
|
Muted: [0, 0, 0],
|
||||||
LightMuted: [0, 0, 0],
|
LightMuted: [0, 0, 0],
|
||||||
Vibrant: [0, 0, 0],
|
Vibrant: [0, 0, 0],
|
||||||
LightVibrant: [0, 0, 0],
|
LightVibrant: [0, 0, 0],
|
||||||
DarkMuted: [238, 238, 238],
|
DarkMuted: [238, 238, 238],
|
||||||
DarkVibrant: [238, 238, 238],
|
DarkVibrant: [238, 238, 238],
|
||||||
})}
|
}))}
|
||||||
/>
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<main className="font-sans flex flex-col h-screen">
|
<main className="font-sans flex flex-col h-screen">
|
||||||
|
@ -6,9 +6,10 @@ import { Helmet } from "react-helmet";
|
|||||||
|
|
||||||
import MasonryGallery from "../components/MasonryGallery";
|
import MasonryGallery from "../components/MasonryGallery";
|
||||||
import KeywordsPicker from "../components/KeywordsPicker";
|
import KeywordsPicker from "../components/KeywordsPicker";
|
||||||
import { getGalleryPageUrl, getHelmetSafeBodyStyle } from "../utils";
|
import { getGalleryPageUrl, getHelmetSafeBodyStyle, getVibrantStyle } from "../utils";
|
||||||
import Nav from "../components/Nav";
|
import Nav from "../components/Nav";
|
||||||
import { Item, Select } from "../components/Select";
|
import { Item, Select } from "../components/Select";
|
||||||
|
import { Switch } from "../components/Switch";
|
||||||
|
|
||||||
const SORT_KEYS = {
|
const SORT_KEYS = {
|
||||||
hue: ["fields", "imageMeta", "vibrantHue"],
|
hue: ["fields", "imageMeta", "vibrantHue"],
|
||||||
@ -31,6 +32,7 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
|||||||
const showDebug =
|
const showDebug =
|
||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
window.location.search.includes("debug=true");
|
window.location.search.includes("debug=true");
|
||||||
|
const [showPalette, setShowPalette] = React.useState(false);
|
||||||
|
|
||||||
const setKeyword = React.useCallback(
|
const setKeyword = React.useCallback(
|
||||||
(newKeyword: string | null) => {
|
(newKeyword: string | null) => {
|
||||||
@ -166,14 +168,14 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
|||||||
<body
|
<body
|
||||||
className="bg-white transition-color"
|
className="bg-white transition-color"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
style={getHelmetSafeBodyStyle({
|
style={getHelmetSafeBodyStyle(getVibrantStyle({
|
||||||
Muted: [0, 0, 0],
|
Muted: [0, 0, 0],
|
||||||
LightMuted: [0, 0, 0],
|
LightMuted: [0, 0, 0],
|
||||||
Vibrant: [0, 0, 0],
|
Vibrant: [0, 0, 0],
|
||||||
LightVibrant: [0, 0, 0],
|
LightVibrant: [0, 0, 0],
|
||||||
DarkMuted: [238, 238, 238],
|
DarkMuted: [238, 238, 238],
|
||||||
DarkVibrant: [238, 238, 238],
|
DarkVibrant: [238, 238, 238],
|
||||||
})}
|
}))}
|
||||||
/>
|
/>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<div className="top-0 z-10">
|
<div className="top-0 z-10">
|
||||||
@ -186,7 +188,7 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col md:flex-row md:items-end justify-between px-4 md:px-8 sm:mx-auto">
|
<div className="flex flex-col lg:flex-row lg:items-end justify-between px-4 md:px-8 sm:mx-auto">
|
||||||
<KeywordsPicker
|
<KeywordsPicker
|
||||||
keywords={[
|
keywords={[
|
||||||
"Boyce Thompson Arboretum",
|
"Boyce Thompson Arboretum",
|
||||||
@ -207,7 +209,13 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
|||||||
onChange={setKeyword}
|
onChange={setKeyword}
|
||||||
value={filterKeyword}
|
value={filterKeyword}
|
||||||
/>
|
/>
|
||||||
<div className="m-2">
|
<div className="m-2 flex flex-row items-end">
|
||||||
|
<Switch
|
||||||
|
isSelected={showPalette}
|
||||||
|
onChange={(val) => setShowPalette(val)}
|
||||||
|
>
|
||||||
|
Show palettes
|
||||||
|
</Switch>
|
||||||
<Select
|
<Select
|
||||||
label="Sort by..."
|
label="Sort by..."
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -238,42 +246,50 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
|||||||
sortKey,
|
sortKey,
|
||||||
filterKeyword,
|
filterKeyword,
|
||||||
}}
|
}}
|
||||||
|
showPalette={showPalette}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const query = graphql`query GalleryPageQuery {
|
export const query = graphql`
|
||||||
allFile(
|
query GalleryPageQuery {
|
||||||
filter: {sourceInstanceName: {eq: "gallery"}}
|
allFile(
|
||||||
sort: {fields: {imageMeta: {dateTaken: DESC}}}
|
filter: { sourceInstanceName: { eq: "gallery" } }
|
||||||
) {
|
sort: { fields: { imageMeta: { dateTaken: DESC } } }
|
||||||
nodes {
|
) {
|
||||||
relativePath
|
nodes {
|
||||||
base
|
relativePath
|
||||||
childImageSharp {
|
base
|
||||||
fluid {
|
childImageSharp {
|
||||||
aspectRatio
|
fluid {
|
||||||
}
|
aspectRatio
|
||||||
gatsbyImageData(layout: CONSTRAINED, height: 550, placeholder: DOMINANT_COLOR)
|
|
||||||
}
|
|
||||||
fields {
|
|
||||||
imageMeta {
|
|
||||||
vibrantHue
|
|
||||||
dominantHue
|
|
||||||
dateTaken
|
|
||||||
meta {
|
|
||||||
Keywords
|
|
||||||
Rating
|
|
||||||
ObjectName
|
|
||||||
}
|
}
|
||||||
vibrant {
|
gatsbyImageData(
|
||||||
Vibrant
|
layout: CONSTRAINED
|
||||||
|
height: 550
|
||||||
|
placeholder: DOMINANT_COLOR
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fields {
|
||||||
|
imageMeta {
|
||||||
|
vibrantHue
|
||||||
|
dominantHue
|
||||||
|
dateTaken
|
||||||
|
meta {
|
||||||
|
Keywords
|
||||||
|
Rating
|
||||||
|
ObjectName
|
||||||
|
}
|
||||||
|
vibrant {
|
||||||
|
# Vibrant
|
||||||
|
...VibrantColors
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`;
|
`;
|
||||||
|
|
||||||
export default GalleryPage;
|
export default GalleryPage;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// import kebabCase from 'lodash/kebabCase';
|
// import kebabCase from 'lodash/kebabCase';
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
import { HomepageImage } from "./pages";
|
import { HomepageImage } from "./pages";
|
||||||
import { GalleryImage } from "./pages/photogallery";
|
import { GalleryImage } from "./pages/photogallery";
|
||||||
|
|
||||||
@ -35,8 +36,7 @@ export const getVibrantStyle = (vibrant: Queries.FileFieldsImageMetaVibrant, scr
|
|||||||
});
|
});
|
||||||
|
|
||||||
// work around SSR bug in react-helmet
|
// work around SSR bug in react-helmet
|
||||||
export const getHelmetSafeBodyStyle = (vibrant: Queries.FileFieldsImageMetaVibrant, screenHeight?: number) => {
|
export const getHelmetSafeBodyStyle = (style: React.CSSProperties) => {
|
||||||
const style = getVibrantStyle(vibrant, screenHeight);
|
|
||||||
if (typeof window === "undefined") {
|
if (typeof window === "undefined") {
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
@ -6506,7 +6506,7 @@ __metadata:
|
|||||||
react-cool-dimensions: ^2.0.7
|
react-cool-dimensions: ^2.0.7
|
||||||
react-div-100vh: ^0.7.0
|
react-div-100vh: ^0.7.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
react-helmet: ^6.1.0
|
react-helmet: latest
|
||||||
react-stately: ^3.19.0
|
react-stately: ^3.19.0
|
||||||
react-tiny-popover: ^7.2.0
|
react-tiny-popover: ^7.2.0
|
||||||
sass: ^1.34.0
|
sass: ^1.34.0
|
||||||
@ -13794,7 +13794,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-helmet@npm:^6.1.0":
|
"react-helmet@npm:latest":
|
||||||
version: 6.1.0
|
version: 6.1.0
|
||||||
resolution: "react-helmet@npm:6.1.0"
|
resolution: "react-helmet@npm:6.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user