solve type errors
This commit is contained in:
parent
b2afb0abfe
commit
18dad7cb0b
@ -19,8 +19,9 @@ module.exports = {
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
rules: {
|
||||
"no-undef": 0,
|
||||
"react/prop-types": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-unused-vars": 0,
|
||||
"react/jsx-sort-props": 1,
|
||||
},
|
||||
};
|
||||
|
@ -21,6 +21,9 @@
|
||||
"deploy": "yarn build && yarn upload",
|
||||
"pretty": "prettier --write ."
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "^17.0.38"
|
||||
},
|
||||
"dependencies": {
|
||||
"@adobe/react-spectrum": "^3.19.0",
|
||||
"@mdx-js/mdx": "^1.6.22",
|
||||
@ -71,6 +74,7 @@
|
||||
"@types/ramda": "^0.28.15",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
||||
"@typescript-eslint/parser": "^5.39.0",
|
||||
"cross-env": "^7.0.3",
|
||||
|
@ -1,7 +1,12 @@
|
||||
import * as React from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
const KeywordsPicker = ({ keywords, value, onChange }) => {
|
||||
interface KeywordsPickerProps {
|
||||
keywords: string[];
|
||||
value: string | null;
|
||||
onChange: (val: string | null) => void;
|
||||
}
|
||||
const KeywordsPicker = ({ keywords, value, onChange }: KeywordsPickerProps) => {
|
||||
return (
|
||||
<div className="mx-2">
|
||||
<span className="text-xs text-[#A2A2A2]">Collections</span>
|
@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import { Link, Node } from "gatsby";
|
||||
import { GatsbyImage, getImage, ImageDataLike } from "gatsby-plugin-image";
|
||||
import { Link } from "gatsby";
|
||||
import { GatsbyImage, getImage } from "gatsby-plugin-image";
|
||||
import * as R from "ramda";
|
||||
import { getAspectRatio, getName } from "../utils";
|
||||
import useBreakpoint from "use-breakpoint";
|
||||
@ -8,6 +8,7 @@ import useBreakpoint from "use-breakpoint";
|
||||
// @ts-ignore
|
||||
import themeBreakpoints from "../breakpoints";
|
||||
import classNames from "classnames";
|
||||
import { GalleryImage } from "../pages/photogallery";
|
||||
|
||||
interface Row {
|
||||
aspect: number;
|
||||
@ -16,7 +17,7 @@ interface Row {
|
||||
}
|
||||
|
||||
interface MasonryGalleryProps {
|
||||
images: (ImageDataLike & Node)[];
|
||||
images: (GalleryImage)[];
|
||||
aspectsByBreakpoint: {
|
||||
[breakpoint: string]: number;
|
||||
}
|
||||
@ -40,9 +41,9 @@ const MasonryGallery = ({
|
||||
const { breakpoint } = useBreakpoint(breakpoints, "sm");
|
||||
|
||||
const aspectRatios = React.useMemo(
|
||||
() => R.map(getAspectRatio, images),
|
||||
() => R.map(getAspectRatio, images).filter(Boolean),
|
||||
[images]
|
||||
);
|
||||
) as number[];
|
||||
|
||||
const targetAspect = aspectTargetsByBreakpoint[breakpoint];
|
||||
const rows = React.useMemo(
|
||||
@ -115,6 +116,7 @@ const MasonryGallery = ({
|
||||
const widthNumber = ((ar / rowAspectRatioSum) * 100).toFixed(7);
|
||||
width = `${widthNumber}%`;
|
||||
}
|
||||
// @ts-ignore
|
||||
const img = getImage(image);
|
||||
return (
|
||||
<Link
|
||||
@ -136,9 +138,9 @@ const MasonryGallery = ({
|
||||
// borderColor: `rgb(${image.fields.imageMeta.vibrant.Vibrant.join(',')})`
|
||||
borderColor: debugHue
|
||||
? `hsl(
|
||||
${image.fields.imageMeta.dominantHue[0]},
|
||||
${image.fields.imageMeta.dominantHue[1] * 100}%,
|
||||
${image.fields.imageMeta.dominantHue[2] * 100}%
|
||||
${image.fields?.imageMeta?.dominantHue?.[0]},
|
||||
${image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100}%,
|
||||
${image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100}%
|
||||
)`
|
||||
: "black",
|
||||
}}
|
||||
@ -147,14 +149,14 @@ const MasonryGallery = ({
|
||||
{debugHue && (
|
||||
<span className="text-white z-20 absolute bg-black">
|
||||
hsl(
|
||||
{image.fields.imageMeta.dominantHue[0]},{" "}
|
||||
{(image.fields.imageMeta.dominantHue[1] * 100).toFixed(2)}%,{" "}
|
||||
{(image.fields.imageMeta.dominantHue[2] * 100).toFixed(2)}% )
|
||||
{image.fields?.imageMeta?.dominantHue?.[0]},{" "}
|
||||
{(image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100).toFixed(2)}%,{" "}
|
||||
{(image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100).toFixed(2)}% )
|
||||
</span>
|
||||
)}
|
||||
{debugRating && (
|
||||
<span className="text-white z-20 absolute bg-black">
|
||||
rating: {image.fields.imageMeta.meta.Rating}
|
||||
rating: {image.fields?.imageMeta?.meta?.Rating}
|
||||
</span>
|
||||
)}
|
||||
{img && (
|
||||
|
@ -5,7 +5,16 @@ import useDimensions from "react-cool-dimensions";
|
||||
|
||||
import Menu from "@spectrum-icons/workflow/Menu";
|
||||
|
||||
const Nav = ({ isClient, internalLinks, className }) => {
|
||||
interface NavProps {
|
||||
isClient?: boolean;
|
||||
className?: string;
|
||||
internalLinks: {
|
||||
href: string;
|
||||
label: string;
|
||||
}[]
|
||||
}
|
||||
|
||||
const Nav = ({ isClient, internalLinks, className }: NavProps) => {
|
||||
const { observe, currentBreakpoint } = useDimensions({
|
||||
breakpoints: { XS: 0, LG: 690 },
|
||||
updateOnBreakpointChange: true,
|
4424
src/gatsby-types.d.ts
vendored
Normal file
4424
src/gatsby-types.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
src/global.d.ts
vendored
Normal file
4
src/global.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/* eslint-disable */
|
||||
declare interface Window {
|
||||
plausible: any;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import * as R from "ramda";
|
||||
import { graphql } from "gatsby";
|
||||
import { graphql, PageProps } from "gatsby";
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Picker, Item } from "@adobe/react-spectrum";
|
||||
|
||||
@ -14,22 +14,25 @@ const SORT_KEYS = {
|
||||
rating: ["fields", "imageMeta", "meta", "Rating"],
|
||||
hue_debug: ["fields", "imageMeta", "dominantHue", 0],
|
||||
date: [],
|
||||
};
|
||||
} as const;
|
||||
|
||||
const GalleryPage = ({ data }) => {
|
||||
export type GalleryImage =
|
||||
Queries.GalleryPageQueryQuery["allFile"]["nodes"][number];
|
||||
|
||||
const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
|
||||
const hash =
|
||||
typeof window !== "undefined" ? window.location.hash.replace("#", "") : "";
|
||||
|
||||
const [hashCleared, setHashCleared] = React.useState(false); // eslint-disable-line no-unused-vars
|
||||
// ^ used just to force a re-render with the cleared hash value (I know, it's a smell for sure)
|
||||
const [filterKeyword, _setKeyword] = React.useState(null);
|
||||
const [sortKey, _setSortKey] = React.useState("rating");
|
||||
const [filterKeyword, _setKeyword] = React.useState(null as string | null);
|
||||
const [sortKey, _setSortKey] = React.useState("rating" as string);
|
||||
const showDebug =
|
||||
typeof window !== "undefined" &&
|
||||
window.location.search.includes("debug=true");
|
||||
|
||||
const setKeyword = React.useCallback(
|
||||
(newKeyword) => {
|
||||
(newKeyword: string | null) => {
|
||||
if (newKeyword) {
|
||||
try {
|
||||
window.plausible("Filter Keyword", {
|
||||
@ -50,7 +53,7 @@ const GalleryPage = ({ data }) => {
|
||||
);
|
||||
|
||||
const setSortKey = React.useCallback(
|
||||
(newSortKey) => {
|
||||
(newSortKey: string) => {
|
||||
try {
|
||||
window.plausible("Sort Gallery", {
|
||||
props: { key: newSortKey },
|
||||
@ -102,12 +105,12 @@ const GalleryPage = ({ data }) => {
|
||||
|
||||
const sortKeyFromUrl = url.searchParams.get("sort");
|
||||
if (sortKeyFromUrl) {
|
||||
_setSortKey(sortKeyFromUrl, false);
|
||||
_setSortKey(sortKeyFromUrl);
|
||||
}
|
||||
|
||||
const filterKeyFromUrl = url.searchParams.get("filter");
|
||||
if (filterKeyFromUrl) {
|
||||
_setKeyword(filterKeyFromUrl, false);
|
||||
_setKeyword(filterKeyFromUrl);
|
||||
}
|
||||
|
||||
// hacky but it works for now
|
||||
@ -117,34 +120,41 @@ const GalleryPage = ({ data }) => {
|
||||
}, 100);
|
||||
}, [setSortKey, setKeyword, scrollIntoView]);
|
||||
|
||||
const images = React.useMemo(
|
||||
const images: GalleryImage[] = React.useMemo(
|
||||
() =>
|
||||
R.pipe(
|
||||
// @ts-ignore
|
||||
sortKey === "date"
|
||||
? R.sort((node1, node2) => {
|
||||
? R.sort((node1: typeof data["allFile"]["nodes"][number], node2) => {
|
||||
const date1 = new Date(
|
||||
// @ts-ignore
|
||||
R.path(["fields", "imageMeta", "dateTaken"], node1)
|
||||
);
|
||||
const date2 = new Date(
|
||||
// @ts-ignore
|
||||
R.path(["fields", "imageMeta", "dateTaken"], node2)
|
||||
);
|
||||
return -1 * (date1.getTime() - date2.getTime());
|
||||
})
|
||||
: R.sort(R.descend(R.path(SORT_KEYS[sortKey]))),
|
||||
: // @ts-ignore
|
||||
R.sort(R.descend(R.path(SORT_KEYS[sortKey]))),
|
||||
filterKeyword
|
||||
? R.filter((image) =>
|
||||
// @ts-ignore
|
||||
R.includes(
|
||||
filterKeyword,
|
||||
// @ts-ignore
|
||||
R.path(["fields", "imageMeta", "meta", "Keywords"], image)
|
||||
)
|
||||
)
|
||||
: R.identity
|
||||
)(data.allFile.nodes),
|
||||
)(data.allFile.nodes) as any,
|
||||
[data, sortKey, filterKeyword]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* @ts-ignore */}
|
||||
<Helmet>
|
||||
<title>Photo Gallery | Chuck Dries</title>
|
||||
<body className="bg-black text-white" />
|
||||
@ -156,8 +166,7 @@ const GalleryPage = ({ data }) => {
|
||||
{ href: "/", label: "Home" },
|
||||
{ href: "/photogallery/", label: "Gallery" },
|
||||
]}
|
||||
>
|
||||
</Nav>
|
||||
></Nav>
|
||||
<div className="flex flex-col md:flex-row md:items-end justify-between">
|
||||
<h1 className="text-5xl mt-0 ml-5 mr-5 font-serif font-black z-10">
|
||||
Photo Gallery
|
||||
@ -182,13 +191,17 @@ const GalleryPage = ({ data }) => {
|
||||
<div className="m-2">
|
||||
<Picker
|
||||
label="Sort by..."
|
||||
// @ts-ignore
|
||||
onSelectionChange={setSortKey}
|
||||
selectedKey={sortKey}
|
||||
>
|
||||
<Item key="rating">Default</Item>
|
||||
<Item key="date">Date</Item>
|
||||
<Item key="hue">Hue</Item>
|
||||
{showDebug && <Item key="hue_debug">Dominant hue[debug]</Item>}
|
||||
<>{/* @ts-ignore */}</>
|
||||
{showDebug ? (
|
||||
<Item key="hue_debug">Dominant hue[debug]</Item>
|
||||
) : undefined}
|
||||
</Picker>
|
||||
</div>
|
||||
</div>
|
36
src/utils.ts
36
src/utils.ts
@ -1,28 +1,30 @@
|
||||
// import kebabCase from 'lodash/kebabCase';
|
||||
|
||||
export const getMeta = (image) => image.fields.imageMeta;
|
||||
import { GalleryImage } from "./pages/photogallery";
|
||||
|
||||
export const getName = (image) =>
|
||||
export const getMeta = (image: GalleryImage) => image.fields?.imageMeta;
|
||||
|
||||
export const getName = (image: GalleryImage) =>
|
||||
getMeta(image)?.meta?.ObjectName || image.base;
|
||||
|
||||
// some pleasing default colors for SSR and initial hydration
|
||||
export const getVibrant = (image) => getMeta(image)?.vibrant;
|
||||
export const getVibrant = (image: GalleryImage) => getMeta(image)?.vibrant;
|
||||
|
||||
export const hasName = (image) => Boolean(getMeta(image)?.meta?.ObjectName);
|
||||
export const hasName = (image: GalleryImage) => Boolean(getMeta(image)?.meta?.ObjectName);
|
||||
|
||||
export const getAspectRatio = (image) =>
|
||||
image.childImageSharp.fluid.aspectRatio;
|
||||
export const getAspectRatio = (image: GalleryImage): number =>
|
||||
image.childImageSharp?.fluid?.aspectRatio ?? 1;
|
||||
|
||||
export const getCanonicalSize = (image) => ({
|
||||
height: image.childImageSharp.gatsbyImageData.height,
|
||||
width: image.childImageSharp.gatsbyImageData.width,
|
||||
export const getCanonicalSize = (image: GalleryImage) => ({
|
||||
height: image.childImageSharp?.gatsbyImageData.height,
|
||||
width: image.childImageSharp?.gatsbyImageData.width,
|
||||
});
|
||||
|
||||
export const getRgba = (palette, alpha) =>
|
||||
export const getRgba = (palette: string[], alpha: number) =>
|
||||
`rgba(${palette[0]}, ${palette[1]}, ${palette[2]}, ${alpha || 1})`;
|
||||
|
||||
// work around SSR bug in react-helmet
|
||||
export const getHelmetSafeBodyStyle = (vibrant, screenHeight?: number) => {
|
||||
export const getHelmetSafeBodyStyle = (vibrant: Queries.FileFieldsImageMetaVibrant, screenHeight?: number) => {
|
||||
const style = {
|
||||
"--muted": vibrant.Muted,
|
||||
"--dark-muted": vibrant.DarkMuted,
|
||||
@ -36,11 +38,12 @@ export const getHelmetSafeBodyStyle = (vibrant, screenHeight?: number) => {
|
||||
return style;
|
||||
}
|
||||
return Object.keys(style)
|
||||
// @ts-ignore
|
||||
.map((key) => `${key}: ${style[key]};`)
|
||||
.join("");
|
||||
};
|
||||
|
||||
const gcd = (a, b) => {
|
||||
const gcd = (a: number, b: number): number => {
|
||||
if (b < 0.0000001) {
|
||||
return a; // Since there is a limited precision we need to limit the value.
|
||||
}
|
||||
@ -48,7 +51,7 @@ const gcd = (a, b) => {
|
||||
return gcd(b, Math.floor(a % b)); // Discard any fractions due to limitations in precision.
|
||||
};
|
||||
|
||||
export const getShutterFractionFromExposureTime = (exposureTime) => {
|
||||
export const getShutterFractionFromExposureTime = (exposureTime: number) => {
|
||||
if (exposureTime === 0.03333333333333333) {
|
||||
return "1/30";
|
||||
}
|
||||
@ -80,7 +83,12 @@ export const getShutterFractionFromExposureTime = (exposureTime) => {
|
||||
return `${numerator}/${denominator}`;
|
||||
};
|
||||
|
||||
export const getGalleryPageUrl = ({ keyword, sortKey }, hash) => {
|
||||
interface galleryPageUrlProps {
|
||||
keyword: string | null;
|
||||
sortKey: string;
|
||||
}
|
||||
|
||||
export const getGalleryPageUrl = ({ keyword, sortKey }: galleryPageUrlProps, hash: string) => {
|
||||
const url = new URL(
|
||||
`${
|
||||
typeof window !== "undefined"
|
||||
|
15
yarn.lock
15
yarn.lock
@ -4903,10 +4903,17 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
version "17.0.43"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.43.tgz"
|
||||
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==
|
||||
"@types/react-helmet@^6.1.5":
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083"
|
||||
integrity sha512-/ICuy7OHZxR0YCAZLNg9r7I9aijWUWvxaPR6uTuyxe8tAj5RL4Sw1+R6NhXUtOsarkGYPmaHdBDvuXh2DIN/uA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^17.0.38":
|
||||
version "17.0.50"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.50.tgz#39abb4f7098f546cfcd6b51207c90c4295ee81fc"
|
||||
integrity sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
|
Loading…
x
Reference in New Issue
Block a user