Merge branch 'scrolling-stuff' into main
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								.yarn/cache/@types-lodash-npm-4.14.191-67a04a969b-ba0d5434e1.zip
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.yarn/cache/@types-lodash-npm-4.14.191-67a04a969b-ba0d5434e1.zip
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								.yarn/cache/@types-lodash.debounce-npm-4.0.7-efe92bf273-e873b2d77f.zip
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.yarn/cache/@types-lodash.debounce-npm-4.0.7-efe92bf273-e873b2d77f.zip
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC00003.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC00003.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC00015.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC00015.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC00159-2.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC00159-2.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC05702.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC05702.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC06124.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC06124.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC06719.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC06719.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC06803.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC06803.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC08086.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC08086.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC08103.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC08103.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC08222.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC08222.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC08263.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC08263.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC09447.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC09447.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								data/gallery/DSC09454.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/gallery/DSC09454.jpg
									 (Stored with Git LFS)
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -14,6 +14,41 @@ export const onRouteUpdate = function () { | ||||
|     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 { MDXProvider } from '@mdx-js/react'; | ||||
|  | ||||
|   | ||||
| @@ -41,6 +41,7 @@ | ||||
|     "gatsby-source-filesystem": "^5.0.0", | ||||
|     "gatsby-transformer-sharp": "^5.0.0", | ||||
|     "kebab-case": "^1.0.1", | ||||
|     "lodash.debounce": "^4.0.8", | ||||
|     "node-iptc": "^1.0.5", | ||||
|     "node-vibrant": "3.1.6", | ||||
|     "postcss": "^8.4.19", | ||||
| @@ -60,6 +61,7 @@ | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@types/chroma-js": "^2.1.4", | ||||
|     "@types/lodash.debounce": "^4.0.7", | ||||
|     "@types/node": "^18.8.3", | ||||
|     "@types/ramda": "^0.28.15", | ||||
|     "@types/react": "^18.0.21", | ||||
|   | ||||
| @@ -65,7 +65,10 @@ const GalleryImage = ({ data, location: { state } }) => { | ||||
|  | ||||
|   useEffect(() => { | ||||
|     requestAnimationFrame(() => { | ||||
|       window.scrollTo(0, 180); | ||||
|       window.scrollTo({ | ||||
|         top: 180, | ||||
|         behavior: 'smooth' | ||||
|       }); | ||||
|     }); | ||||
|   }, [image.base]); | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,7 @@ interface MasonryGalleryProps { | ||||
|     [breakpoint: string]: number; | ||||
|   }; | ||||
|   debugHue?: boolean; | ||||
|   dataFn?: (image: GalleryImage) => (string | null); | ||||
|   dataFn?: (image: GalleryImage) => string[] | null; | ||||
|   linkState?: object; | ||||
|   showPalette?: boolean; | ||||
|   singleRow?: boolean; | ||||
| @@ -47,14 +47,8 @@ const MasonryGallery = ({ | ||||
|     [aspectTargetsByBreakpoint] | ||||
|   ); | ||||
|  | ||||
|   // const { observe, currentBreakpoint } = useDimensions({ | ||||
|   //   breakpoints, | ||||
|   // }); | ||||
|  | ||||
|   const { breakpoint } = useBreakpoint(breakpoints, "xs"); | ||||
|   console.log("🚀 ~ file: MasonryGallery.tsx:55 ~ breakpoint:", breakpoint) | ||||
|  | ||||
|   // const breakpoint = currentBreakpoint.length ? currentBreakpoint : "xs"; | ||||
|   const galleryWidth = `calc(100vw - ${ | ||||
|     breakpoint === "xs" || breakpoint === "sm" ? "32" : "160" | ||||
|   }px)`; | ||||
| @@ -78,7 +72,7 @@ const MasonryGallery = ({ | ||||
|       // does adding current image to our row get us closer to our target aspect ratio? | ||||
|       if (currentDiff > diffIfImageIsAddedToCurrentRow) { | ||||
|         currentRow.aspect += currentAspect; | ||||
|         currentRow.images += 1 | ||||
|         currentRow.images += 1; | ||||
|         // _rows.push(currentRow); | ||||
|         continue; | ||||
|       } | ||||
| @@ -91,8 +85,8 @@ const MasonryGallery = ({ | ||||
|       _rows.push({ | ||||
|         aspect: currentAspect, | ||||
|         images: 1, | ||||
|         startIndex: currentRow.startIndex + currentRow.images | ||||
|       }) | ||||
|         startIndex: currentRow.startIndex + currentRow.images, | ||||
|       }); | ||||
|     } | ||||
|  | ||||
|     return R.indexBy(R.prop("startIndex"), _rows); | ||||
| @@ -125,7 +119,7 @@ const MasonryGallery = ({ | ||||
|         } | ||||
|         const rowAspectRatioSum = currentRow.aspect; | ||||
|         const ar = getAspectRatio(image); | ||||
|         let width; | ||||
|         let width: string; | ||||
|         let height = `calc(${galleryWidth} / ${rowAspectRatioSum} ${ | ||||
|           showPalette ? "+ 10px" : "- 10px" | ||||
|         })`; | ||||
| @@ -144,7 +138,7 @@ const MasonryGallery = ({ | ||||
|         const data = dataFn ? dataFn(image) : null; | ||||
|         return ( | ||||
|           <Link | ||||
|             className={classNames("border-8 border-white overflow-hidden")} | ||||
|           className={classNames("border-8 border-white overflow-hidden relative")} | ||||
|             id={image.base} | ||||
|             key={`${image.base}`} | ||||
|             state={{ | ||||
| @@ -165,9 +159,18 @@ const MasonryGallery = ({ | ||||
|             }} | ||||
|             to={`/photogallery/${image.base}/`} | ||||
|           > | ||||
|               {data && <span className="text-white z-20 absolute bg-black"> | ||||
|                 {data} | ||||
|               </span>} | ||||
|             {data && ( | ||||
|               <div className="text-white z-20 absolute flex flex-col items-start"> | ||||
|                 {data.map((dataString, i) => ( | ||||
|                   <span | ||||
|                     className="bg-black/30 backdrop-blur p-[2px] m-[2px] max-w-full" | ||||
|                     key={i} | ||||
|                   > | ||||
|                     {dataString} | ||||
|                   </span> | ||||
|                 ))} | ||||
|               </div> | ||||
|             )} | ||||
|             {img && ( | ||||
|               <div | ||||
|                 className={`h-full ${ | ||||
|   | ||||
							
								
								
									
										33
									
								
								src/components/ToggleButton.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/components/ToggleButton.tsx
									
									
									
									
									
										Normal 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
									
									
								
							
							
						
						
									
										356
									
								
								src/gatsby-types.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -1532,7 +1532,6 @@ type Query = { | ||||
|   readonly allSiteFunction: SiteFunctionConnection; | ||||
|   readonly allSitePage: SitePageConnection; | ||||
|   readonly allSitePlugin: SitePluginConnection; | ||||
|   readonly allStaticImage: StaticImageConnection; | ||||
|   readonly directory: Maybe<Directory>; | ||||
|   readonly file: Maybe<File>; | ||||
|   readonly imageSharp: Maybe<ImageSharp>; | ||||
| @@ -1541,7 +1540,6 @@ type Query = { | ||||
|   readonly siteFunction: Maybe<SiteFunction>; | ||||
|   readonly sitePage: Maybe<SitePage>; | ||||
|   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 = { | ||||
|   absolutePath: InputMaybe<StringQueryOperatorInput>; | ||||
|   accessTime: InputMaybe<DateQueryOperatorInput>; | ||||
| @@ -1786,46 +1776,6 @@ type Query_sitePluginArgs = { | ||||
|   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 & { | ||||
|   readonly buildTime: Maybe<Scalars['Date']>; | ||||
|   readonly children: ReadonlyArray<Node>; | ||||
| @@ -2592,312 +2542,6 @@ type SortOrderEnum = | ||||
|   | 'ASC' | ||||
|   | '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 = { | ||||
|   readonly eq: InputMaybe<Scalars['String']>; | ||||
|   readonly glob: InputMaybe<Scalars['String']>; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import * as React from "react"; | ||||
| import * as R from "ramda"; | ||||
| import { graphql, Link, navigate, PageProps } from "gatsby"; | ||||
| import { Helmet } from "react-helmet"; | ||||
| import debounce from "lodash.debounce"; | ||||
| // import { Picker, Item } from "@adobe/react-spectrum"; | ||||
|  | ||||
| import MasonryGallery from "../components/MasonryGallery"; | ||||
| @@ -16,6 +17,7 @@ import Nav from "../components/Nav"; | ||||
| import { Item, Select } from "../components/Select"; | ||||
| import { Switch } from "../components/Switch"; | ||||
| import ColorPalette from "@spectrum-icons/workflow/ColorPalette"; | ||||
| import { ToggleButton } from "../components/ToggleButton"; | ||||
|  | ||||
| const SORT_KEYS = { | ||||
|   hue: ["fields", "imageMeta", "vibrantHue"], | ||||
| @@ -79,8 +81,8 @@ const GalleryPage = ({ | ||||
|         getGalleryPageUrl( | ||||
|           { sortKey: newSortKey, keyword: filterKeyword, showDebug }, | ||||
|           hash | ||||
|         ), | ||||
|         { replace: true } | ||||
|         ) | ||||
|         // { replace: true } | ||||
|       ); | ||||
|     }, | ||||
|     [filterKeyword, hash, showDebug] | ||||
| @@ -90,21 +92,18 @@ const GalleryPage = ({ | ||||
|     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); | ||||
|     navigate( | ||||
|       getGalleryPageUrl({ sortKey, keyword: filterKeyword, showDebug }, ""), | ||||
|       { replace: true } | ||||
|     ); | ||||
|     window.removeEventListener("scroll", removeHash); | ||||
|   }, [hash, sortKey, filterKeyword, showDebug]); | ||||
|  | ||||
|   React.useEffect(() => { | ||||
|     window.addEventListener("wheel", removeHash); | ||||
|     return () => window.removeEventListener("wheel", removeHash); | ||||
|     // window.addEventListener("scroll", removeHash); | ||||
|     return () => { | ||||
|       window.removeEventListener("scroll", removeHash); | ||||
|     }; | ||||
|   }, [removeHash]); | ||||
|  | ||||
|   React.useEffect(() => { | ||||
| @@ -119,12 +118,16 @@ const GalleryPage = ({ | ||||
|         console.log("⚠️failed to find hash"); | ||||
|         return; | ||||
|       } | ||||
|       console.log("scrolling into view manually"); | ||||
|       console.log("scrolling into view manually", el.offsetTop); | ||||
|       el.scrollIntoView({ | ||||
|         block: hash.startsWith("all") ? "start" : "center", | ||||
|         behavior: "smooth", | ||||
|       }); | ||||
|       setTimeout(() => { | ||||
|         window.addEventListener("scroll", removeHash); | ||||
|       }, 100); | ||||
|     }); | ||||
|   }, [hash]); | ||||
|   }, [hash, removeHash]); | ||||
|  | ||||
|   const images: GalleryImage[] = React.useMemo(() => { | ||||
|     const sort = | ||||
| @@ -166,24 +169,43 @@ const GalleryPage = ({ | ||||
|     ); | ||||
|   }, [data]); | ||||
|  | ||||
|   const [dbgTags, setDbgTags] = React.useState(false); | ||||
|   const [dbgSortKey, setDbgSortKey] = React.useState(false); | ||||
|   const [dbgName, setDbgName] = React.useState(false); | ||||
|   const dataFn = React.useCallback( | ||||
|     (image: GalleryImage): string | null => { | ||||
|     (image: GalleryImage): string[] | null => { | ||||
|       if (!showDebug) { | ||||
|         return null; | ||||
|       } | ||||
|       if (sortKey === "rating") { | ||||
|         return `[${R.pathOr(null, SORT_KEYS.rating, image)}] ${image.base}`; | ||||
|       let data: string[] = []; | ||||
|       if (dbgName) { | ||||
|         data.push(image.base); | ||||
|       } | ||||
|       if (sortKey === "datePublished") { | ||||
|         const date = R.pathOr(null, SORT_KEYS.datePublished, image); | ||||
|         if (!date) { | ||||
|           return null; | ||||
|       if (dbgSortKey) { | ||||
|         switch (sortKey) { | ||||
|           case "hue": | ||||
|           case "rating": { | ||||
|             data.push(R.pathOr("x", SORT_KEYS[sortKey], image)); | ||||
|             break; | ||||
|           } | ||||
|         return new Date(date).toLocaleString(); | ||||
|           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"); | ||||
|             } | ||||
|       return null; | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       if (dbgTags) { | ||||
|         data.push(image.fields?.imageMeta?.meta?.Keywords?.join(",") ?? "x"); | ||||
|       } | ||||
|       return data; | ||||
|     }, | ||||
|     [showDebug, sortKey] | ||||
|     [showDebug, sortKey, dbgName, dbgSortKey, dbgTags] | ||||
|   ); | ||||
|  | ||||
|   return ( | ||||
| @@ -276,7 +298,20 @@ const GalleryPage = ({ | ||||
|             onPick={onKeywordPick} | ||||
|             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"> | ||||
|               <Switch | ||||
|                 isSelected={showPalette} | ||||
| @@ -292,7 +327,7 @@ const GalleryPage = ({ | ||||
|             </div> | ||||
|             <Select | ||||
|               label="Sort by..." | ||||
|               // @ts-ignore | ||||
|               // @ts-expect-error React.key, but string is more convenient for the state | ||||
|               onSelectionChange={setSortKey} | ||||
|               selectedKey={sortKey} | ||||
|             > | ||||
|   | ||||
| @@ -8,7 +8,9 @@ | ||||
|  | ||||
| * { | ||||
|   box-sizing: border-box; | ||||
|   scroll-behavior: smooth; | ||||
| } | ||||
| :root { | ||||
|   /* scroll-behavior: smooth; */ | ||||
| } | ||||
| /* .hero * { | ||||
|   transition: color .2s, background-color .2s; | ||||
| @@ -92,6 +94,7 @@ | ||||
|  | ||||
| body { | ||||
|   @apply bg-gray-100; | ||||
|   overflow: auto; | ||||
|   /* @apply bg-black; */ | ||||
|   /* @apply text-white; */ | ||||
| } | ||||
|   | ||||
							
								
								
									
										28
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/utils.ts
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| import React from "react"; | ||||
| import React, { useCallback, useRef } from "react"; | ||||
|  | ||||
| import { pathOr } from "ramda"; | ||||
| // import kebabCase from 'lodash/kebabCase'; | ||||
| @@ -150,3 +150,29 @@ export function compareDates<T>( | ||||
|   const diff = -1 * (date1.getTime() - date2.getTime()); | ||||
|   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] | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										18
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -4560,6 +4560,22 @@ __metadata: | ||||
|   languageName: node | ||||
|   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": | ||||
|   version: 4.14.170 | ||||
|   resolution: "@types/lodash@npm:4.14.170" | ||||
| @@ -6464,6 +6480,7 @@ __metadata: | ||||
|     "@react-spectrum/provider": ^3.6.0 | ||||
|     "@spectrum-icons/workflow": ^4.0.4 | ||||
|     "@types/chroma-js": ^2.1.4 | ||||
|     "@types/lodash.debounce": ^4.0.7 | ||||
|     "@types/node": ^18.8.3 | ||||
|     "@types/ramda": ^0.28.15 | ||||
|     "@types/react": ^18.0.21 | ||||
| @@ -6495,6 +6512,7 @@ __metadata: | ||||
|     gatsby-source-filesystem: ^5.0.0 | ||||
|     gatsby-transformer-sharp: ^5.0.0 | ||||
|     kebab-case: ^1.0.1 | ||||
|     lodash.debounce: ^4.0.8 | ||||
|     node-iptc: ^1.0.5 | ||||
|     node-vibrant: 3.1.6 | ||||
|     postcss: ^8.4.19 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user