import * as React from "react"; import * as R from "ramda"; import { graphql, Link, navigate, PageProps } from "gatsby"; import { Helmet } from "react-helmet"; // import { Picker, Item } from "@adobe/react-spectrum"; import MasonryGallery from "../components/MasonryGallery"; import KeywordsPicker from "../components/KeywordsPicker"; import { compareDates, getGalleryPageUrl, getHelmetSafeBodyStyle, getVibrantStyle, } from "../utils"; import Nav from "../components/Nav"; import { Item, Select } from "../components/Select"; import { Switch } from "../components/Switch"; import ColorPalette from "@spectrum-icons/workflow/ColorPalette"; const SORT_KEYS = { hue: ["fields", "imageMeta", "vibrantHue"], rating: ["fields", "imageMeta", "meta", "Rating"], // hue_debug: ["fields", "imageMeta", "dominantHue", 0], hue_debug: ["fields", "imageMeta", "dominantHue", "0"], date: ["fields", "imageMeta", "dateTaken"], datePublished: ["fields", "imageMeta", "datePublished"], } as const; export type GalleryImage = Queries.GalleryPageQueryQuery["all"]["nodes"][number]; function smartCompareDates( key: keyof typeof SORT_KEYS, left: GalleryImage, right: GalleryImage ) { let diff = compareDates(SORT_KEYS[key], left, right); if (diff !== 0) { return diff; } return compareDates(SORT_KEYS.date, left, right); } const GalleryPage = ({ data, location, }: PageProps) => { const hash = location.hash ? location.hash.replace("#", "") : ""; const params = new URLSearchParams(location.search); const filterKeyword = params.get("filter"); const sortKey = params.get("sort") ?? "rating"; const showDebug = Boolean(params.get("debug")?.length); const [showPalette, setShowPalette] = React.useState(false); const onKeywordPick = React.useCallback((newKeyword: string | null) => { if (newKeyword) { try { window.plausible("Filter Keyword", { props: { keyword: newKeyword }, }); } catch (e) { // do nothing } } }, []); const setSortKey = React.useCallback( (newSortKey: string) => { try { window.plausible("Sort Gallery", { props: { key: newSortKey }, }); } catch (e) { // do nothing } navigate( getGalleryPageUrl( { sortKey: newSortKey, keyword: filterKeyword, showDebug }, hash ), { replace: true } ); }, [filterKeyword, hash, showDebug] ); const removeHash = React.useCallback(() => { if (!hash.length) { return; } // const url = new URL( // typeof window !== "undefined" // ? window.location.href.toString() // : "https://chuckdries.com/photogallery/" // ); // url.hash = ""; // window.history.replaceState(null, "", url.href.toString()); navigate(getGalleryPageUrl({ sortKey, keyword: filterKeyword, showDebug}, ""), { replace: true }) window.removeEventListener("wheel", removeHash); window.removeEventListener("touchmove", removeHash); }, [hash, sortKey, filterKeyword, showDebug]); React.useEffect(() => { window.addEventListener("wheel", removeHash); window.addEventListener("touchmove", removeHash); return () => { window.removeEventListener("wheel", removeHash); window.removeEventListener("touchmove", removeHash); } }, [removeHash]); React.useEffect(() => { // hacky but it works for now requestAnimationFrame(() => { // don't scroll into view if user got here with back button or if we just cleared it if (!hash.length) { return; } const el = document.getElementById(hash); if (!el) { console.log("⚠️failed to find hash"); return; } console.log("scrolling into view manually"); el.scrollIntoView({ block: hash.startsWith("all") ? "start" : "center", }); }); }, [hash]); const images: GalleryImage[] = React.useMemo(() => { const sort = sortKey === "date" || sortKey === "datePublished" ? R.sort((node1: typeof data["all"]["nodes"][number], node2) => smartCompareDates(sortKey, node1, node2) ) : R.sort( // @ts-ignore R.descend(R.path(SORT_KEYS[sortKey])) ); const filter = filterKeyword ? R.filter((image) => R.includes( filterKeyword, R.pathOr([], ["fields", "imageMeta", "meta", "Keywords"], image) ) ) : R.identity; try { const ret = R.pipe( // @ts-ignore sort, filter )(data.all.nodes) as any; return ret; } catch (e) { console.log("caught images!", e); return []; } }, [data, sortKey, filterKeyword]); const recents = React.useMemo(() => { return R.sort( (left, right) => smartCompareDates("datePublished", left, right), data.recents.nodes ); }, [data]); const dataFn = React.useCallback( (image: GalleryImage): string | null => { if (!showDebug) { return null; } if (sortKey === "rating") { return `[${R.pathOr(null, SORT_KEYS.rating, image)}] ${image.base}`; } if (sortKey === "datePublished") { const date = R.pathOr(null, SORT_KEYS.datePublished, image); if (!date) { return null; } return new Date(date).toLocaleString(); } return null; }, [showDebug, sortKey] ); return ( <> {/* @ts-ignore */} Photo Gallery | Chuck Dries

Recently published

{sortKey !== "datePublished" && ( show more )}

All images

selected ? getGalleryPageUrl({ keyword: null, sortKey, showDebug }, hash) : getGalleryPageUrl({ keyword: val, sortKey, showDebug }, hash) } keywords={[ "Boyce Thompson Arboretum", "winter", "night", "coast", // "city", "landscape", "flowers", "product", // "waterfall", // "fireworks", // "panoramic", "Portland Japanese Garden", // "shoot the light", // "sunset", ]} onPick={onKeywordPick} value={filterKeyword} />
setShowPalette(val)} >
); }; export const query = graphql` query GalleryPageQuery { recents: allFile( filter: { sourceInstanceName: { eq: "gallery" } } sort: { fields: { imageMeta: { datePublished: DESC } } } limit: 10 ) { ...GalleryImageFile } all: allFile( filter: { sourceInstanceName: { eq: "gallery" } } sort: { fields: { imageMeta: { dateTaken: DESC } } } ) { ...GalleryImageFile } } fragment GalleryImageFile on FileConnection { nodes { base childImageSharp { fluid { aspectRatio } gatsbyImageData( layout: CONSTRAINED height: 550 placeholder: DOMINANT_COLOR ) } fields { imageMeta { vibrantHue dominantHue dateTaken datePublished meta { Keywords Rating ObjectName CreateDate ModifyDate } vibrant { ...VibrantColors } } } } } `; export default GalleryPage;