Merge branch 'scrolling-stuff' into main

This commit is contained in:
2023-03-11 00:13:01 -08:00
25 changed files with 229 additions and 427 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -14,6 +14,41 @@ export const onRouteUpdate = function () {
window.plausible("pageview"); window.plausible("pageview");
} }
}; };
// docs say you can return a scroll position from this fn, but that's a bold-faced lie
export const shouldUpdateScroll = ({
prevRouterProps,
routerProps: { location },
pathname,
}) => {
if (pathname.startsWith('/photogallery/') && pathname !== '/photogallery/' ) {
// if (prevRouterProps?.location.pathname === '/photogallery/') {
// console.log('scroll to image from gallery')
// // setTimeout(() => {
// // window.scrollTo(0, 0);
// // }, 100)
// setTimeout(() => {
// window.scrollTo(0, 180);
// }, 10)
// } else {
// console.log('scroll to image from elsewhere')
// requestAnimationFrame(() => {
// window.scrollTo(0, 180);
// })
// }
console.log('gallery image, skipping')
return false;
}
if (prevRouterProps?.location.pathname === pathname) {
return false;
}
if (pathname === "/photogallery/" && location.hash.length) {
return false;
}
return true;
}
// import * as React from 'react'; // import * as React from 'react';
// import { MDXProvider } from '@mdx-js/react'; // import { MDXProvider } from '@mdx-js/react';

View File

@@ -41,6 +41,7 @@
"gatsby-source-filesystem": "^5.0.0", "gatsby-source-filesystem": "^5.0.0",
"gatsby-transformer-sharp": "^5.0.0", "gatsby-transformer-sharp": "^5.0.0",
"kebab-case": "^1.0.1", "kebab-case": "^1.0.1",
"lodash.debounce": "^4.0.8",
"node-iptc": "^1.0.5", "node-iptc": "^1.0.5",
"node-vibrant": "3.1.6", "node-vibrant": "3.1.6",
"postcss": "^8.4.19", "postcss": "^8.4.19",
@@ -60,6 +61,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/chroma-js": "^2.1.4", "@types/chroma-js": "^2.1.4",
"@types/lodash.debounce": "^4.0.7",
"@types/node": "^18.8.3", "@types/node": "^18.8.3",
"@types/ramda": "^0.28.15", "@types/ramda": "^0.28.15",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",

View File

@@ -65,7 +65,10 @@ const GalleryImage = ({ data, location: { state } }) => {
useEffect(() => { useEffect(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
window.scrollTo(0, 180); window.scrollTo({
top: 180,
behavior: 'smooth'
});
}); });
}, [image.base]); }, [image.base]);

View File

@@ -23,7 +23,7 @@ interface MasonryGalleryProps {
[breakpoint: string]: number; [breakpoint: string]: number;
}; };
debugHue?: boolean; debugHue?: boolean;
dataFn?: (image: GalleryImage) => (string | null); dataFn?: (image: GalleryImage) => string[] | null;
linkState?: object; linkState?: object;
showPalette?: boolean; showPalette?: boolean;
singleRow?: boolean; singleRow?: boolean;
@@ -47,14 +47,8 @@ const MasonryGallery = ({
[aspectTargetsByBreakpoint] [aspectTargetsByBreakpoint]
); );
// const { observe, currentBreakpoint } = useDimensions({
// breakpoints,
// });
const { breakpoint } = useBreakpoint(breakpoints, "xs"); const { breakpoint } = useBreakpoint(breakpoints, "xs");
console.log("🚀 ~ file: MasonryGallery.tsx:55 ~ breakpoint:", breakpoint)
// const breakpoint = currentBreakpoint.length ? currentBreakpoint : "xs";
const galleryWidth = `calc(100vw - ${ const galleryWidth = `calc(100vw - ${
breakpoint === "xs" || breakpoint === "sm" ? "32" : "160" breakpoint === "xs" || breakpoint === "sm" ? "32" : "160"
}px)`; }px)`;
@@ -78,7 +72,7 @@ const MasonryGallery = ({
// does adding current image to our row get us closer to our target aspect ratio? // does adding current image to our row get us closer to our target aspect ratio?
if (currentDiff > diffIfImageIsAddedToCurrentRow) { if (currentDiff > diffIfImageIsAddedToCurrentRow) {
currentRow.aspect += currentAspect; currentRow.aspect += currentAspect;
currentRow.images += 1 currentRow.images += 1;
// _rows.push(currentRow); // _rows.push(currentRow);
continue; continue;
} }
@@ -91,8 +85,8 @@ const MasonryGallery = ({
_rows.push({ _rows.push({
aspect: currentAspect, aspect: currentAspect,
images: 1, images: 1,
startIndex: currentRow.startIndex + currentRow.images startIndex: currentRow.startIndex + currentRow.images,
}) });
} }
return R.indexBy(R.prop("startIndex"), _rows); return R.indexBy(R.prop("startIndex"), _rows);
@@ -125,7 +119,7 @@ const MasonryGallery = ({
} }
const rowAspectRatioSum = currentRow.aspect; const rowAspectRatioSum = currentRow.aspect;
const ar = getAspectRatio(image); const ar = getAspectRatio(image);
let width; let width: string;
let height = `calc(${galleryWidth} / ${rowAspectRatioSum} ${ let height = `calc(${galleryWidth} / ${rowAspectRatioSum} ${
showPalette ? "+ 10px" : "- 10px" showPalette ? "+ 10px" : "- 10px"
})`; })`;
@@ -144,7 +138,7 @@ const MasonryGallery = ({
const data = dataFn ? dataFn(image) : null; const data = dataFn ? dataFn(image) : null;
return ( return (
<Link <Link
className={classNames("border-8 border-white overflow-hidden")} className={classNames("border-8 border-white overflow-hidden relative")}
id={image.base} id={image.base}
key={`${image.base}`} key={`${image.base}`}
state={{ state={{
@@ -165,9 +159,18 @@ const MasonryGallery = ({
}} }}
to={`/photogallery/${image.base}/`} to={`/photogallery/${image.base}/`}
> >
{data && <span className="text-white z-20 absolute bg-black"> {data && (
{data} <div className="text-white z-20 absolute flex flex-col items-start">
</span>} {data.map((dataString, i) => (
<span
className="bg-black/30 backdrop-blur p-[2px] m-[2px] max-w-full"
key={i}
>
{dataString}
</span>
))}
</div>
)}
{img && ( {img && (
<div <div
className={`h-full ${ className={`h-full ${

View File

@@ -0,0 +1,33 @@
import * as React from 'react';
import {useToggleState} from 'react-stately';
import {AriaToggleButtonProps, useToggleButton} from 'react-aria';
import {useRef} from 'react';
import classNames from 'classnames';
export function ToggleButton(props: AriaToggleButtonProps) {
let ref = useRef(null);
let state = useToggleState(props);
let { buttonProps, isPressed } = useToggleButton(props, state, ref);
return (
<button
{...buttonProps}
className={classNames(buttonProps.className, "py-[3px] px-2 mx-1 rounded")}
ref={ref}
style={{
background: isPressed
? state.isSelected ? 'darkgreen' : 'gray'
: state.isSelected
? 'green'
: 'lightgray',
color: state.isSelected ? 'white' : 'black',
userSelect: 'none',
WebkitUserSelect: 'none',
border: 'none'
}}
>
{props.children}
</button>
);
}

356
src/gatsby-types.d.ts vendored
View File

@@ -1532,7 +1532,6 @@ type Query = {
readonly allSiteFunction: SiteFunctionConnection; readonly allSiteFunction: SiteFunctionConnection;
readonly allSitePage: SitePageConnection; readonly allSitePage: SitePageConnection;
readonly allSitePlugin: SitePluginConnection; readonly allSitePlugin: SitePluginConnection;
readonly allStaticImage: StaticImageConnection;
readonly directory: Maybe<Directory>; readonly directory: Maybe<Directory>;
readonly file: Maybe<File>; readonly file: Maybe<File>;
readonly imageSharp: Maybe<ImageSharp>; readonly imageSharp: Maybe<ImageSharp>;
@@ -1541,7 +1540,6 @@ type Query = {
readonly siteFunction: Maybe<SiteFunction>; readonly siteFunction: Maybe<SiteFunction>;
readonly sitePage: Maybe<SitePage>; readonly sitePage: Maybe<SitePage>;
readonly sitePlugin: Maybe<SitePlugin>; readonly sitePlugin: Maybe<SitePlugin>;
readonly staticImage: Maybe<StaticImage>;
}; };
@@ -1609,14 +1607,6 @@ type Query_allSitePluginArgs = {
}; };
type Query_allStaticImageArgs = {
filter: InputMaybe<StaticImageFilterInput>;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
sort: InputMaybe<ReadonlyArray<InputMaybe<StaticImageSortInput>>>;
};
type Query_directoryArgs = { type Query_directoryArgs = {
absolutePath: InputMaybe<StringQueryOperatorInput>; absolutePath: InputMaybe<StringQueryOperatorInput>;
accessTime: InputMaybe<DateQueryOperatorInput>; accessTime: InputMaybe<DateQueryOperatorInput>;
@@ -1786,46 +1776,6 @@ type Query_sitePluginArgs = {
version: InputMaybe<StringQueryOperatorInput>; version: InputMaybe<StringQueryOperatorInput>;
}; };
type Query_staticImageArgs = {
absolutePath: InputMaybe<StringQueryOperatorInput>;
accessTime: InputMaybe<DateQueryOperatorInput>;
atime: InputMaybe<DateQueryOperatorInput>;
atimeMs: InputMaybe<FloatQueryOperatorInput>;
base: InputMaybe<StringQueryOperatorInput>;
birthTime: InputMaybe<DateQueryOperatorInput>;
birthtime: InputMaybe<DateQueryOperatorInput>;
birthtimeMs: InputMaybe<FloatQueryOperatorInput>;
blksize: InputMaybe<IntQueryOperatorInput>;
blocks: InputMaybe<IntQueryOperatorInput>;
changeTime: InputMaybe<DateQueryOperatorInput>;
children: InputMaybe<NodeFilterListInput>;
ctime: InputMaybe<DateQueryOperatorInput>;
ctimeMs: InputMaybe<FloatQueryOperatorInput>;
dev: InputMaybe<IntQueryOperatorInput>;
dir: InputMaybe<StringQueryOperatorInput>;
ext: InputMaybe<StringQueryOperatorInput>;
extension: InputMaybe<StringQueryOperatorInput>;
id: InputMaybe<StringQueryOperatorInput>;
ino: InputMaybe<IntQueryOperatorInput>;
internal: InputMaybe<InternalFilterInput>;
mode: InputMaybe<IntQueryOperatorInput>;
modifiedTime: InputMaybe<DateQueryOperatorInput>;
mtime: InputMaybe<DateQueryOperatorInput>;
mtimeMs: InputMaybe<FloatQueryOperatorInput>;
name: InputMaybe<StringQueryOperatorInput>;
nlink: InputMaybe<IntQueryOperatorInput>;
parent: InputMaybe<NodeFilterInput>;
prettySize: InputMaybe<StringQueryOperatorInput>;
rdev: InputMaybe<IntQueryOperatorInput>;
relativeDirectory: InputMaybe<StringQueryOperatorInput>;
relativePath: InputMaybe<StringQueryOperatorInput>;
root: InputMaybe<StringQueryOperatorInput>;
size: InputMaybe<IntQueryOperatorInput>;
sourceInstanceName: InputMaybe<StringQueryOperatorInput>;
uid: InputMaybe<IntQueryOperatorInput>;
};
type Site = Node & { type Site = Node & {
readonly buildTime: Maybe<Scalars['Date']>; readonly buildTime: Maybe<Scalars['Date']>;
readonly children: ReadonlyArray<Node>; readonly children: ReadonlyArray<Node>;
@@ -2592,312 +2542,6 @@ type SortOrderEnum =
| 'ASC' | 'ASC'
| 'DESC'; | 'DESC';
type StaticImage = Node & {
readonly absolutePath: Maybe<Scalars['String']>;
readonly accessTime: Maybe<Scalars['Date']>;
readonly atime: Maybe<Scalars['Date']>;
readonly atimeMs: Maybe<Scalars['Float']>;
readonly base: Maybe<Scalars['String']>;
readonly birthTime: Maybe<Scalars['Date']>;
readonly birthtime: Maybe<Scalars['Date']>;
readonly birthtimeMs: Maybe<Scalars['Float']>;
readonly blksize: Maybe<Scalars['Int']>;
readonly blocks: Maybe<Scalars['Int']>;
readonly changeTime: Maybe<Scalars['Date']>;
readonly children: ReadonlyArray<Node>;
readonly ctime: Maybe<Scalars['Date']>;
readonly ctimeMs: Maybe<Scalars['Float']>;
readonly dev: Maybe<Scalars['Int']>;
readonly dir: Maybe<Scalars['String']>;
readonly ext: Maybe<Scalars['String']>;
readonly extension: Maybe<Scalars['String']>;
readonly id: Scalars['ID'];
readonly ino: Maybe<Scalars['Int']>;
readonly internal: Internal;
readonly mode: Maybe<Scalars['Int']>;
readonly modifiedTime: Maybe<Scalars['Date']>;
readonly mtime: Maybe<Scalars['Date']>;
readonly mtimeMs: Maybe<Scalars['Float']>;
readonly name: Maybe<Scalars['String']>;
readonly nlink: Maybe<Scalars['Int']>;
readonly parent: Maybe<Node>;
readonly prettySize: Maybe<Scalars['String']>;
readonly rdev: Maybe<Scalars['Int']>;
readonly relativeDirectory: Maybe<Scalars['String']>;
readonly relativePath: Maybe<Scalars['String']>;
readonly root: Maybe<Scalars['String']>;
readonly size: Maybe<Scalars['Int']>;
readonly sourceInstanceName: Maybe<Scalars['String']>;
readonly uid: Maybe<Scalars['Int']>;
};
type StaticImage_accessTimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_atimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_birthTimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_birthtimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_changeTimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_ctimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_modifiedTimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImage_mtimeArgs = {
difference: InputMaybe<Scalars['String']>;
formatString: InputMaybe<Scalars['String']>;
fromNow: InputMaybe<Scalars['Boolean']>;
locale: InputMaybe<Scalars['String']>;
};
type StaticImageConnection = {
readonly distinct: ReadonlyArray<Scalars['String']>;
readonly edges: ReadonlyArray<StaticImageEdge>;
readonly group: ReadonlyArray<StaticImageGroupConnection>;
readonly max: Maybe<Scalars['Float']>;
readonly min: Maybe<Scalars['Float']>;
readonly nodes: ReadonlyArray<StaticImage>;
readonly pageInfo: PageInfo;
readonly sum: Maybe<Scalars['Float']>;
readonly totalCount: Scalars['Int'];
};
type StaticImageConnection_distinctArgs = {
field: StaticImageFieldSelector;
};
type StaticImageConnection_groupArgs = {
field: StaticImageFieldSelector;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
};
type StaticImageConnection_maxArgs = {
field: StaticImageFieldSelector;
};
type StaticImageConnection_minArgs = {
field: StaticImageFieldSelector;
};
type StaticImageConnection_sumArgs = {
field: StaticImageFieldSelector;
};
type StaticImageEdge = {
readonly next: Maybe<StaticImage>;
readonly node: StaticImage;
readonly previous: Maybe<StaticImage>;
};
type StaticImageFieldSelector = {
readonly absolutePath: InputMaybe<FieldSelectorEnum>;
readonly accessTime: InputMaybe<FieldSelectorEnum>;
readonly atime: InputMaybe<FieldSelectorEnum>;
readonly atimeMs: InputMaybe<FieldSelectorEnum>;
readonly base: InputMaybe<FieldSelectorEnum>;
readonly birthTime: InputMaybe<FieldSelectorEnum>;
readonly birthtime: InputMaybe<FieldSelectorEnum>;
readonly birthtimeMs: InputMaybe<FieldSelectorEnum>;
readonly blksize: InputMaybe<FieldSelectorEnum>;
readonly blocks: InputMaybe<FieldSelectorEnum>;
readonly changeTime: InputMaybe<FieldSelectorEnum>;
readonly children: InputMaybe<NodeFieldSelector>;
readonly ctime: InputMaybe<FieldSelectorEnum>;
readonly ctimeMs: InputMaybe<FieldSelectorEnum>;
readonly dev: InputMaybe<FieldSelectorEnum>;
readonly dir: InputMaybe<FieldSelectorEnum>;
readonly ext: InputMaybe<FieldSelectorEnum>;
readonly extension: InputMaybe<FieldSelectorEnum>;
readonly id: InputMaybe<FieldSelectorEnum>;
readonly ino: InputMaybe<FieldSelectorEnum>;
readonly internal: InputMaybe<InternalFieldSelector>;
readonly mode: InputMaybe<FieldSelectorEnum>;
readonly modifiedTime: InputMaybe<FieldSelectorEnum>;
readonly mtime: InputMaybe<FieldSelectorEnum>;
readonly mtimeMs: InputMaybe<FieldSelectorEnum>;
readonly name: InputMaybe<FieldSelectorEnum>;
readonly nlink: InputMaybe<FieldSelectorEnum>;
readonly parent: InputMaybe<NodeFieldSelector>;
readonly prettySize: InputMaybe<FieldSelectorEnum>;
readonly rdev: InputMaybe<FieldSelectorEnum>;
readonly relativeDirectory: InputMaybe<FieldSelectorEnum>;
readonly relativePath: InputMaybe<FieldSelectorEnum>;
readonly root: InputMaybe<FieldSelectorEnum>;
readonly size: InputMaybe<FieldSelectorEnum>;
readonly sourceInstanceName: InputMaybe<FieldSelectorEnum>;
readonly uid: InputMaybe<FieldSelectorEnum>;
};
type StaticImageFilterInput = {
readonly absolutePath: InputMaybe<StringQueryOperatorInput>;
readonly accessTime: InputMaybe<DateQueryOperatorInput>;
readonly atime: InputMaybe<DateQueryOperatorInput>;
readonly atimeMs: InputMaybe<FloatQueryOperatorInput>;
readonly base: InputMaybe<StringQueryOperatorInput>;
readonly birthTime: InputMaybe<DateQueryOperatorInput>;
readonly birthtime: InputMaybe<DateQueryOperatorInput>;
readonly birthtimeMs: InputMaybe<FloatQueryOperatorInput>;
readonly blksize: InputMaybe<IntQueryOperatorInput>;
readonly blocks: InputMaybe<IntQueryOperatorInput>;
readonly changeTime: InputMaybe<DateQueryOperatorInput>;
readonly children: InputMaybe<NodeFilterListInput>;
readonly ctime: InputMaybe<DateQueryOperatorInput>;
readonly ctimeMs: InputMaybe<FloatQueryOperatorInput>;
readonly dev: InputMaybe<IntQueryOperatorInput>;
readonly dir: InputMaybe<StringQueryOperatorInput>;
readonly ext: InputMaybe<StringQueryOperatorInput>;
readonly extension: InputMaybe<StringQueryOperatorInput>;
readonly id: InputMaybe<StringQueryOperatorInput>;
readonly ino: InputMaybe<IntQueryOperatorInput>;
readonly internal: InputMaybe<InternalFilterInput>;
readonly mode: InputMaybe<IntQueryOperatorInput>;
readonly modifiedTime: InputMaybe<DateQueryOperatorInput>;
readonly mtime: InputMaybe<DateQueryOperatorInput>;
readonly mtimeMs: InputMaybe<FloatQueryOperatorInput>;
readonly name: InputMaybe<StringQueryOperatorInput>;
readonly nlink: InputMaybe<IntQueryOperatorInput>;
readonly parent: InputMaybe<NodeFilterInput>;
readonly prettySize: InputMaybe<StringQueryOperatorInput>;
readonly rdev: InputMaybe<IntQueryOperatorInput>;
readonly relativeDirectory: InputMaybe<StringQueryOperatorInput>;
readonly relativePath: InputMaybe<StringQueryOperatorInput>;
readonly root: InputMaybe<StringQueryOperatorInput>;
readonly size: InputMaybe<IntQueryOperatorInput>;
readonly sourceInstanceName: InputMaybe<StringQueryOperatorInput>;
readonly uid: InputMaybe<IntQueryOperatorInput>;
};
type StaticImageGroupConnection = {
readonly distinct: ReadonlyArray<Scalars['String']>;
readonly edges: ReadonlyArray<StaticImageEdge>;
readonly field: Scalars['String'];
readonly fieldValue: Maybe<Scalars['String']>;
readonly group: ReadonlyArray<StaticImageGroupConnection>;
readonly max: Maybe<Scalars['Float']>;
readonly min: Maybe<Scalars['Float']>;
readonly nodes: ReadonlyArray<StaticImage>;
readonly pageInfo: PageInfo;
readonly sum: Maybe<Scalars['Float']>;
readonly totalCount: Scalars['Int'];
};
type StaticImageGroupConnection_distinctArgs = {
field: StaticImageFieldSelector;
};
type StaticImageGroupConnection_groupArgs = {
field: StaticImageFieldSelector;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
};
type StaticImageGroupConnection_maxArgs = {
field: StaticImageFieldSelector;
};
type StaticImageGroupConnection_minArgs = {
field: StaticImageFieldSelector;
};
type StaticImageGroupConnection_sumArgs = {
field: StaticImageFieldSelector;
};
type StaticImageSortInput = {
readonly absolutePath: InputMaybe<SortOrderEnum>;
readonly accessTime: InputMaybe<SortOrderEnum>;
readonly atime: InputMaybe<SortOrderEnum>;
readonly atimeMs: InputMaybe<SortOrderEnum>;
readonly base: InputMaybe<SortOrderEnum>;
readonly birthTime: InputMaybe<SortOrderEnum>;
readonly birthtime: InputMaybe<SortOrderEnum>;
readonly birthtimeMs: InputMaybe<SortOrderEnum>;
readonly blksize: InputMaybe<SortOrderEnum>;
readonly blocks: InputMaybe<SortOrderEnum>;
readonly changeTime: InputMaybe<SortOrderEnum>;
readonly children: InputMaybe<NodeSortInput>;
readonly ctime: InputMaybe<SortOrderEnum>;
readonly ctimeMs: InputMaybe<SortOrderEnum>;
readonly dev: InputMaybe<SortOrderEnum>;
readonly dir: InputMaybe<SortOrderEnum>;
readonly ext: InputMaybe<SortOrderEnum>;
readonly extension: InputMaybe<SortOrderEnum>;
readonly id: InputMaybe<SortOrderEnum>;
readonly ino: InputMaybe<SortOrderEnum>;
readonly internal: InputMaybe<InternalSortInput>;
readonly mode: InputMaybe<SortOrderEnum>;
readonly modifiedTime: InputMaybe<SortOrderEnum>;
readonly mtime: InputMaybe<SortOrderEnum>;
readonly mtimeMs: InputMaybe<SortOrderEnum>;
readonly name: InputMaybe<SortOrderEnum>;
readonly nlink: InputMaybe<SortOrderEnum>;
readonly parent: InputMaybe<NodeSortInput>;
readonly prettySize: InputMaybe<SortOrderEnum>;
readonly rdev: InputMaybe<SortOrderEnum>;
readonly relativeDirectory: InputMaybe<SortOrderEnum>;
readonly relativePath: InputMaybe<SortOrderEnum>;
readonly root: InputMaybe<SortOrderEnum>;
readonly size: InputMaybe<SortOrderEnum>;
readonly sourceInstanceName: InputMaybe<SortOrderEnum>;
readonly uid: InputMaybe<SortOrderEnum>;
};
type StringQueryOperatorInput = { type StringQueryOperatorInput = {
readonly eq: InputMaybe<Scalars['String']>; readonly eq: InputMaybe<Scalars['String']>;
readonly glob: InputMaybe<Scalars['String']>; readonly glob: InputMaybe<Scalars['String']>;

View File

@@ -2,6 +2,7 @@ import * as React from "react";
import * as R from "ramda"; import * as R from "ramda";
import { graphql, Link, navigate, PageProps } from "gatsby"; import { graphql, Link, navigate, PageProps } from "gatsby";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import debounce from "lodash.debounce";
// import { Picker, Item } from "@adobe/react-spectrum"; // import { Picker, Item } from "@adobe/react-spectrum";
import MasonryGallery from "../components/MasonryGallery"; import MasonryGallery from "../components/MasonryGallery";
@@ -16,6 +17,7 @@ import Nav from "../components/Nav";
import { Item, Select } from "../components/Select"; import { Item, Select } from "../components/Select";
import { Switch } from "../components/Switch"; import { Switch } from "../components/Switch";
import ColorPalette from "@spectrum-icons/workflow/ColorPalette"; import ColorPalette from "@spectrum-icons/workflow/ColorPalette";
import { ToggleButton } from "../components/ToggleButton";
const SORT_KEYS = { const SORT_KEYS = {
hue: ["fields", "imageMeta", "vibrantHue"], hue: ["fields", "imageMeta", "vibrantHue"],
@@ -79,8 +81,8 @@ const GalleryPage = ({
getGalleryPageUrl( getGalleryPageUrl(
{ sortKey: newSortKey, keyword: filterKeyword, showDebug }, { sortKey: newSortKey, keyword: filterKeyword, showDebug },
hash hash
), )
{ replace: true } // { replace: true }
); );
}, },
[filterKeyword, hash, showDebug] [filterKeyword, hash, showDebug]
@@ -90,21 +92,18 @@ const GalleryPage = ({
if (!hash.length) { if (!hash.length) {
return; return;
} }
// const url = new URL( navigate(
// typeof window !== "undefined" getGalleryPageUrl({ sortKey, keyword: filterKeyword, showDebug }, ""),
// ? window.location.href.toString() { replace: true }
// : "https://chuckdries.com/photogallery/" );
// ); window.removeEventListener("scroll", removeHash);
// url.hash = "";
// window.history.replaceState(null, "", url.href.toString());
navigate(getGalleryPageUrl({ sortKey, keyword: filterKeyword, showDebug}, ""), { replace: true })
window.removeEventListener("wheel", removeHash);
}, [hash, sortKey, filterKeyword, showDebug]); }, [hash, sortKey, filterKeyword, showDebug]);
React.useEffect(() => { React.useEffect(() => {
window.addEventListener("wheel", removeHash); // window.addEventListener("scroll", removeHash);
return () => window.removeEventListener("wheel", removeHash); return () => {
window.removeEventListener("scroll", removeHash);
};
}, [removeHash]); }, [removeHash]);
React.useEffect(() => { React.useEffect(() => {
@@ -119,12 +118,16 @@ const GalleryPage = ({
console.log("⚠failed to find hash"); console.log("⚠failed to find hash");
return; return;
} }
console.log("scrolling into view manually"); console.log("scrolling into view manually", el.offsetTop);
el.scrollIntoView({ el.scrollIntoView({
block: hash.startsWith("all") ? "start" : "center", block: hash.startsWith("all") ? "start" : "center",
behavior: "smooth",
}); });
setTimeout(() => {
window.addEventListener("scroll", removeHash);
}, 100);
}); });
}, [hash]); }, [hash, removeHash]);
const images: GalleryImage[] = React.useMemo(() => { const images: GalleryImage[] = React.useMemo(() => {
const sort = const sort =
@@ -166,24 +169,43 @@ const GalleryPage = ({
); );
}, [data]); }, [data]);
const [dbgTags, setDbgTags] = React.useState(false);
const [dbgSortKey, setDbgSortKey] = React.useState(false);
const [dbgName, setDbgName] = React.useState(false);
const dataFn = React.useCallback( const dataFn = React.useCallback(
(image: GalleryImage): string | null => { (image: GalleryImage): string[] | null => {
if (!showDebug) { if (!showDebug) {
return null; return null;
} }
if (sortKey === "rating") { let data: string[] = [];
return `[${R.pathOr(null, SORT_KEYS.rating, image)}] ${image.base}`; if (dbgName) {
data.push(image.base);
} }
if (sortKey === "datePublished") { if (dbgSortKey) {
const date = R.pathOr(null, SORT_KEYS.datePublished, image); switch (sortKey) {
if (!date) { case "hue":
return null; case "rating": {
data.push(R.pathOr("x", SORT_KEYS[sortKey], image));
break;
}
case "date":
case "datePublished": {
const date = R.pathOr(null, SORT_KEYS[sortKey], image);
if (date) {
data.push(new Date(date).toLocaleString());
} else {
data.push("x");
}
break;
}
} }
return new Date(date).toLocaleString();
} }
return null; if (dbgTags) {
data.push(image.fields?.imageMeta?.meta?.Keywords?.join(",") ?? "x");
}
return data;
}, },
[showDebug, sortKey] [showDebug, sortKey, dbgName, dbgSortKey, dbgTags]
); );
return ( return (
@@ -276,7 +298,20 @@ const GalleryPage = ({
onPick={onKeywordPick} onPick={onKeywordPick}
value={filterKeyword} value={filterKeyword}
/> />
<div className="my-2 mr-2 flex flex-row items-end"> <div className="my-2 mx-2 flex flex-row items-end">
{showDebug && (
<div className="mr-2">
<ToggleButton isSelected={dbgName} onChange={setDbgName}>
name
</ToggleButton>
<ToggleButton isSelected={dbgSortKey} onChange={setDbgSortKey}>
sort key
</ToggleButton>
<ToggleButton isSelected={dbgTags} onChange={setDbgTags}>
tags
</ToggleButton>
</div>
)}
<div className="border border-gray-400 rounded mr-2"> <div className="border border-gray-400 rounded mr-2">
<Switch <Switch
isSelected={showPalette} isSelected={showPalette}
@@ -292,7 +327,7 @@ const GalleryPage = ({
</div> </div>
<Select <Select
label="Sort by..." label="Sort by..."
// @ts-ignore // @ts-expect-error React.key, but string is more convenient for the state
onSelectionChange={setSortKey} onSelectionChange={setSortKey}
selectedKey={sortKey} selectedKey={sortKey}
> >

View File

@@ -8,7 +8,9 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
scroll-behavior: smooth; }
:root {
/* scroll-behavior: smooth; */
} }
/* .hero * { /* .hero * {
transition: color .2s, background-color .2s; transition: color .2s, background-color .2s;
@@ -92,6 +94,7 @@
body { body {
@apply bg-gray-100; @apply bg-gray-100;
overflow: auto;
/* @apply bg-black; */ /* @apply bg-black; */
/* @apply text-white; */ /* @apply text-white; */
} }

View File

@@ -1,4 +1,4 @@
import React from "react"; import React, { useCallback, useRef } from "react";
import { pathOr } from "ramda"; import { pathOr } from "ramda";
// import kebabCase from 'lodash/kebabCase'; // import kebabCase from 'lodash/kebabCase';
@@ -150,3 +150,29 @@ export function compareDates<T>(
const diff = -1 * (date1.getTime() - date2.getTime()); const diff = -1 * (date1.getTime() - date2.getTime());
return diff; return diff;
} }
/**
* Returns a memoized function that will only call the passed function when it hasn't been called for the wait period
* @param func The function to be called
* @param wait Wait period after function hasn't been called for
* @returns A memoized function that is debounced
*/
export const useDebouncedCallback = (func: Function, wait: number) => {
// Use a ref to store the timeout between renders
// and prevent changes to it from causing re-renders
const timeout = useRef<ReturnType<typeof setTimeout>>();
return useCallback(
(...args: any) => {
const later = () => {
clearTimeout(timeout.current!);
func(...args);
};
clearTimeout(timeout.current ?? undefined);
timeout.current = setTimeout(later, wait);
},
[func, wait]
);
};

View File

@@ -4560,6 +4560,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/lodash.debounce@npm:^4.0.7":
version: 4.0.7
resolution: "@types/lodash.debounce@npm:4.0.7"
dependencies:
"@types/lodash": "*"
checksum: e873b2d77f89010876baba3437ef826b17221b98948e00b5590828334a481dea1c8f9d28543210e564adc53199584f42c3cb171f8b6c3614fefc0b4e0888679c
languageName: node
linkType: hard
"@types/lodash@npm:*":
version: 4.14.191
resolution: "@types/lodash@npm:4.14.191"
checksum: ba0d5434e10690869f32d5ea49095250157cae502f10d57de0a723fd72229ce6c6a4979576f0f13e0aa9fbe3ce2457bfb9fa7d4ec3d6daba56730a51906d1491
languageName: node
linkType: hard
"@types/lodash@npm:^4.14.53": "@types/lodash@npm:^4.14.53":
version: 4.14.170 version: 4.14.170
resolution: "@types/lodash@npm:4.14.170" resolution: "@types/lodash@npm:4.14.170"
@@ -6464,6 +6480,7 @@ __metadata:
"@react-spectrum/provider": ^3.6.0 "@react-spectrum/provider": ^3.6.0
"@spectrum-icons/workflow": ^4.0.4 "@spectrum-icons/workflow": ^4.0.4
"@types/chroma-js": ^2.1.4 "@types/chroma-js": ^2.1.4
"@types/lodash.debounce": ^4.0.7
"@types/node": ^18.8.3 "@types/node": ^18.8.3
"@types/ramda": ^0.28.15 "@types/ramda": ^0.28.15
"@types/react": ^18.0.21 "@types/react": ^18.0.21
@@ -6495,6 +6512,7 @@ __metadata:
gatsby-source-filesystem: ^5.0.0 gatsby-source-filesystem: ^5.0.0
gatsby-transformer-sharp: ^5.0.0 gatsby-transformer-sharp: ^5.0.0
kebab-case: ^1.0.1 kebab-case: ^1.0.1
lodash.debounce: ^4.0.8
node-iptc: ^1.0.5 node-iptc: ^1.0.5
node-vibrant: 3.1.6 node-vibrant: 3.1.6
postcss: ^8.4.19 postcss: ^8.4.19