solve type errors

This commit is contained in:
Chuck Dries 2022-10-10 02:46:54 -07:00
parent b2afb0abfe
commit 18dad7cb0b
No known key found for this signature in database
GPG Key ID: A00B7AEAE1DC5BE6
10 changed files with 4526 additions and 49 deletions

View File

@ -19,8 +19,9 @@ module.exports = {
"plugin:react-hooks/recommended", "plugin:react-hooks/recommended",
], ],
rules: { rules: {
"no-undef": 0,
"react/prop-types": 0, "react/prop-types": 0,
"no-unused-vars": 1, "no-unused-vars": 0,
"react/jsx-sort-props": 1, "react/jsx-sort-props": 1,
}, },
}; };

View File

@ -21,6 +21,9 @@
"deploy": "yarn build && yarn upload", "deploy": "yarn build && yarn upload",
"pretty": "prettier --write ." "pretty": "prettier --write ."
}, },
"resolutions": {
"@types/react": "^17.0.38"
},
"dependencies": { "dependencies": {
"@adobe/react-spectrum": "^3.19.0", "@adobe/react-spectrum": "^3.19.0",
"@mdx-js/mdx": "^1.6.22", "@mdx-js/mdx": "^1.6.22",
@ -71,6 +74,7 @@
"@types/ramda": "^0.28.15", "@types/ramda": "^0.28.15",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/react-helmet": "^6.1.5",
"@typescript-eslint/eslint-plugin": "^5.39.0", "@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0", "@typescript-eslint/parser": "^5.39.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",

View File

@ -1,7 +1,12 @@
import * as React from "react"; import * as React from "react";
import classNames from "classnames"; 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 ( return (
<div className="mx-2"> <div className="mx-2">
<span className="text-xs text-[#A2A2A2]">Collections</span> <span className="text-xs text-[#A2A2A2]">Collections</span>

View File

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { Link, Node } from "gatsby"; import { Link } from "gatsby";
import { GatsbyImage, getImage, ImageDataLike } from "gatsby-plugin-image"; import { GatsbyImage, getImage } from "gatsby-plugin-image";
import * as R from "ramda"; import * as R from "ramda";
import { getAspectRatio, getName } from "../utils"; import { getAspectRatio, getName } from "../utils";
import useBreakpoint from "use-breakpoint"; import useBreakpoint from "use-breakpoint";
@ -8,6 +8,7 @@ import useBreakpoint from "use-breakpoint";
// @ts-ignore // @ts-ignore
import themeBreakpoints from "../breakpoints"; import themeBreakpoints from "../breakpoints";
import classNames from "classnames"; import classNames from "classnames";
import { GalleryImage } from "../pages/photogallery";
interface Row { interface Row {
aspect: number; aspect: number;
@ -16,7 +17,7 @@ interface Row {
} }
interface MasonryGalleryProps { interface MasonryGalleryProps {
images: (ImageDataLike & Node)[]; images: (GalleryImage)[];
aspectsByBreakpoint: { aspectsByBreakpoint: {
[breakpoint: string]: number; [breakpoint: string]: number;
} }
@ -40,9 +41,9 @@ const MasonryGallery = ({
const { breakpoint } = useBreakpoint(breakpoints, "sm"); const { breakpoint } = useBreakpoint(breakpoints, "sm");
const aspectRatios = React.useMemo( const aspectRatios = React.useMemo(
() => R.map(getAspectRatio, images), () => R.map(getAspectRatio, images).filter(Boolean),
[images] [images]
); ) as number[];
const targetAspect = aspectTargetsByBreakpoint[breakpoint]; const targetAspect = aspectTargetsByBreakpoint[breakpoint];
const rows = React.useMemo( const rows = React.useMemo(
@ -115,6 +116,7 @@ const MasonryGallery = ({
const widthNumber = ((ar / rowAspectRatioSum) * 100).toFixed(7); const widthNumber = ((ar / rowAspectRatioSum) * 100).toFixed(7);
width = `${widthNumber}%`; width = `${widthNumber}%`;
} }
// @ts-ignore
const img = getImage(image); const img = getImage(image);
return ( return (
<Link <Link
@ -136,9 +138,9 @@ const MasonryGallery = ({
// borderColor: `rgb(${image.fields.imageMeta.vibrant.Vibrant.join(',')})` // borderColor: `rgb(${image.fields.imageMeta.vibrant.Vibrant.join(',')})`
borderColor: debugHue borderColor: debugHue
? `hsl( ? `hsl(
${image.fields.imageMeta.dominantHue[0]}, ${image.fields?.imageMeta?.dominantHue?.[0]},
${image.fields.imageMeta.dominantHue[1] * 100}%, ${image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100}%,
${image.fields.imageMeta.dominantHue[2] * 100}% ${image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100}%
)` )`
: "black", : "black",
}} }}
@ -147,14 +149,14 @@ const MasonryGallery = ({
{debugHue && ( {debugHue && (
<span className="text-white z-20 absolute bg-black"> <span className="text-white z-20 absolute bg-black">
hsl( hsl(
{image.fields.imageMeta.dominantHue[0]},{" "} {image.fields?.imageMeta?.dominantHue?.[0]},{" "}
{(image.fields.imageMeta.dominantHue[1] * 100).toFixed(2)}%,{" "} {(image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100).toFixed(2)}%,{" "}
{(image.fields.imageMeta.dominantHue[2] * 100).toFixed(2)}% ) {(image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100).toFixed(2)}% )
</span> </span>
)} )}
{debugRating && ( {debugRating && (
<span className="text-white z-20 absolute bg-black"> <span className="text-white z-20 absolute bg-black">
rating: {image.fields.imageMeta.meta.Rating} rating: {image.fields?.imageMeta?.meta?.Rating}
</span> </span>
)} )}
{img && ( {img && (

View File

@ -5,7 +5,16 @@ import useDimensions from "react-cool-dimensions";
import Menu from "@spectrum-icons/workflow/Menu"; 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({ const { observe, currentBreakpoint } = useDimensions({
breakpoints: { XS: 0, LG: 690 }, breakpoints: { XS: 0, LG: 690 },
updateOnBreakpointChange: true, updateOnBreakpointChange: true,

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
View File

@ -0,0 +1,4 @@
/* eslint-disable */
declare interface Window {
plausible: any;
}

View File

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import * as R from "ramda"; import * as R from "ramda";
import { graphql } from "gatsby"; import { graphql, PageProps } from "gatsby";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { Picker, Item } from "@adobe/react-spectrum"; import { Picker, Item } from "@adobe/react-spectrum";
@ -14,22 +14,25 @@ const SORT_KEYS = {
rating: ["fields", "imageMeta", "meta", "Rating"], rating: ["fields", "imageMeta", "meta", "Rating"],
hue_debug: ["fields", "imageMeta", "dominantHue", 0], hue_debug: ["fields", "imageMeta", "dominantHue", 0],
date: [], date: [],
}; } as const;
const GalleryPage = ({ data }) => { export type GalleryImage =
Queries.GalleryPageQueryQuery["allFile"]["nodes"][number];
const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
const hash = const hash =
typeof window !== "undefined" ? window.location.hash.replace("#", "") : ""; typeof window !== "undefined" ? window.location.hash.replace("#", "") : "";
const [hashCleared, setHashCleared] = React.useState(false); // eslint-disable-line no-unused-vars 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) // ^ 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 [filterKeyword, _setKeyword] = React.useState(null as string | null);
const [sortKey, _setSortKey] = React.useState("rating"); const [sortKey, _setSortKey] = React.useState("rating" as string);
const showDebug = const showDebug =
typeof window !== "undefined" && typeof window !== "undefined" &&
window.location.search.includes("debug=true"); window.location.search.includes("debug=true");
const setKeyword = React.useCallback( const setKeyword = React.useCallback(
(newKeyword) => { (newKeyword: string | null) => {
if (newKeyword) { if (newKeyword) {
try { try {
window.plausible("Filter Keyword", { window.plausible("Filter Keyword", {
@ -50,7 +53,7 @@ const GalleryPage = ({ data }) => {
); );
const setSortKey = React.useCallback( const setSortKey = React.useCallback(
(newSortKey) => { (newSortKey: string) => {
try { try {
window.plausible("Sort Gallery", { window.plausible("Sort Gallery", {
props: { key: newSortKey }, props: { key: newSortKey },
@ -102,12 +105,12 @@ const GalleryPage = ({ data }) => {
const sortKeyFromUrl = url.searchParams.get("sort"); const sortKeyFromUrl = url.searchParams.get("sort");
if (sortKeyFromUrl) { if (sortKeyFromUrl) {
_setSortKey(sortKeyFromUrl, false); _setSortKey(sortKeyFromUrl);
} }
const filterKeyFromUrl = url.searchParams.get("filter"); const filterKeyFromUrl = url.searchParams.get("filter");
if (filterKeyFromUrl) { if (filterKeyFromUrl) {
_setKeyword(filterKeyFromUrl, false); _setKeyword(filterKeyFromUrl);
} }
// hacky but it works for now // hacky but it works for now
@ -117,34 +120,41 @@ const GalleryPage = ({ data }) => {
}, 100); }, 100);
}, [setSortKey, setKeyword, scrollIntoView]); }, [setSortKey, setKeyword, scrollIntoView]);
const images = React.useMemo( const images: GalleryImage[] = React.useMemo(
() => () =>
R.pipe( R.pipe(
// @ts-ignore
sortKey === "date" sortKey === "date"
? R.sort((node1, node2) => { ? R.sort((node1: typeof data["allFile"]["nodes"][number], node2) => {
const date1 = new Date( const date1 = new Date(
// @ts-ignore
R.path(["fields", "imageMeta", "dateTaken"], node1) R.path(["fields", "imageMeta", "dateTaken"], node1)
); );
const date2 = new Date( const date2 = new Date(
// @ts-ignore
R.path(["fields", "imageMeta", "dateTaken"], node2) R.path(["fields", "imageMeta", "dateTaken"], node2)
); );
return -1 * (date1.getTime() - date2.getTime()); 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 filterKeyword
? R.filter((image) => ? R.filter((image) =>
// @ts-ignore
R.includes( R.includes(
filterKeyword, filterKeyword,
// @ts-ignore
R.path(["fields", "imageMeta", "meta", "Keywords"], image) R.path(["fields", "imageMeta", "meta", "Keywords"], image)
) )
) )
: R.identity : R.identity
)(data.allFile.nodes), )(data.allFile.nodes) as any,
[data, sortKey, filterKeyword] [data, sortKey, filterKeyword]
); );
return ( return (
<> <>
{/* @ts-ignore */}
<Helmet> <Helmet>
<title>Photo Gallery | Chuck Dries</title> <title>Photo Gallery | Chuck Dries</title>
<body className="bg-black text-white" /> <body className="bg-black text-white" />
@ -156,8 +166,7 @@ const GalleryPage = ({ data }) => {
{ href: "/", label: "Home" }, { href: "/", label: "Home" },
{ href: "/photogallery/", label: "Gallery" }, { href: "/photogallery/", label: "Gallery" },
]} ]}
> ></Nav>
</Nav>
<div className="flex flex-col md:flex-row md:items-end justify-between"> <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"> <h1 className="text-5xl mt-0 ml-5 mr-5 font-serif font-black z-10">
Photo Gallery Photo Gallery
@ -182,13 +191,17 @@ const GalleryPage = ({ data }) => {
<div className="m-2"> <div className="m-2">
<Picker <Picker
label="Sort by..." label="Sort by..."
// @ts-ignore
onSelectionChange={setSortKey} onSelectionChange={setSortKey}
selectedKey={sortKey} selectedKey={sortKey}
> >
<Item key="rating">Default</Item> <Item key="rating">Default</Item>
<Item key="date">Date</Item> <Item key="date">Date</Item>
<Item key="hue">Hue</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> </Picker>
</div> </div>
</div> </div>

View File

@ -1,28 +1,30 @@
// import kebabCase from 'lodash/kebabCase'; // 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; getMeta(image)?.meta?.ObjectName || image.base;
// some pleasing default colors for SSR and initial hydration // 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) => export const getAspectRatio = (image: GalleryImage): number =>
image.childImageSharp.fluid.aspectRatio; image.childImageSharp?.fluid?.aspectRatio ?? 1;
export const getCanonicalSize = (image) => ({ export const getCanonicalSize = (image: GalleryImage) => ({
height: image.childImageSharp.gatsbyImageData.height, height: image.childImageSharp?.gatsbyImageData.height,
width: image.childImageSharp.gatsbyImageData.width, 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})`; `rgba(${palette[0]}, ${palette[1]}, ${palette[2]}, ${alpha || 1})`;
// work around SSR bug in react-helmet // work around SSR bug in react-helmet
export const getHelmetSafeBodyStyle = (vibrant, screenHeight?: number) => { export const getHelmetSafeBodyStyle = (vibrant: Queries.FileFieldsImageMetaVibrant, screenHeight?: number) => {
const style = { const style = {
"--muted": vibrant.Muted, "--muted": vibrant.Muted,
"--dark-muted": vibrant.DarkMuted, "--dark-muted": vibrant.DarkMuted,
@ -36,11 +38,12 @@ export const getHelmetSafeBodyStyle = (vibrant, screenHeight?: number) => {
return style; return style;
} }
return Object.keys(style) return Object.keys(style)
// @ts-ignore
.map((key) => `${key}: ${style[key]};`) .map((key) => `${key}: ${style[key]};`)
.join(""); .join("");
}; };
const gcd = (a, b) => { const gcd = (a: number, b: number): number => {
if (b < 0.0000001) { if (b < 0.0000001) {
return a; // Since there is a limited precision we need to limit the value. 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. 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) { if (exposureTime === 0.03333333333333333) {
return "1/30"; return "1/30";
} }
@ -80,7 +83,12 @@ export const getShutterFractionFromExposureTime = (exposureTime) => {
return `${numerator}/${denominator}`; 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( const url = new URL(
`${ `${
typeof window !== "undefined" typeof window !== "undefined"

View File

@ -4903,10 +4903,17 @@
dependencies: dependencies:
"@types/react" "*" "@types/react" "*"
"@types/react@*": "@types/react-helmet@^6.1.5":
version "17.0.43" version "6.1.5"
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.43.tgz" resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083"
integrity sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A== 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: dependencies:
"@types/prop-types" "*" "@types/prop-types" "*"
"@types/scheduler" "*" "@types/scheduler" "*"