first pass at new homepage design

This commit is contained in:
Chuck Dries 2022-11-17 00:35:48 -08:00
parent 375fc8a9ca
commit ea724c6e3e
No known key found for this signature in database
GPG Key ID: A00B7AEAE1DC5BE6
12 changed files with 1756 additions and 3792 deletions

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { darkTheme, Provider, SSRProvider } from "@adobe/react-spectrum";
import { lightTheme, Provider, SSRProvider } from "@adobe/react-spectrum";
import "./src/styles/global.css";
const env =
@ -30,9 +30,9 @@ export const wrapRootElement = ({ element }) => (
background: "unset",
color: "unset",
}}
colorScheme="dark"
scale="medium"
theme={darkTheme}
colorScheme="light"
// scale="medium"
theme={lightTheme}
>
{element}
</Provider>

View File

@ -8,12 +8,11 @@ module.exports = {
plugins: [
"gatsby-plugin-image",
"gatsby-plugin-react-helmet",
"gatsby-plugin-mdx",
{
resolve: `gatsby-plugin-sharp`,
options: {
defaults: {
quality: 75
quality: 90
}
}
},
@ -43,15 +42,6 @@ module.exports = {
// },
// __key: "pages",
// },
{
resolve: "gatsby-plugin-eslint",
options: {
stages: ["develop"],
extensions: ["js", "jsx"],
exclude: ["node_modules", ".cache", "public"],
// Any eslint-webpack-plugin options below
},
},
"gatsby-plugin-preval",
"gatsby-plugin-robots-txt",
{

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { darkTheme, Provider } from "@adobe/react-spectrum";
import { lightTheme, Provider } from "@adobe/react-spectrum";
import "./src/styles/global.css";
import { SSRProvider } from "@react-aria/ssr";
@ -11,9 +11,9 @@ export const wrapRootElement = ({ element }) => (
color: "unset",
}}
UNSAFE_className="overflow-x-hidden"
colorScheme="dark"
scale="medium"
theme={darkTheme}
colorScheme="light"
// scale="medium"
theme={lightTheme}
>
{element}
</Provider>

View File

@ -21,33 +21,18 @@
"deploy": "yarn build && yarn upload",
"pretty": "prettier --write ."
},
"resolutions": {
"@types/react": "^17.0.38",
"xstate": "4.9.1"
},
"dependencies": {
"@adobe/react-spectrum": "^3.19.0",
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@spectrum-icons/workflow": "^4.0.0",
"autoprefixer": "^10.2.6",
"babel-eslint": "^10.1.0",
"babel-plugin-preval": "^5.0.0",
"chalk": "^4.1.1",
"chroma-js": "^2.1.2",
"classnames": "^2.3.1",
"eslint": "^8.25.0",
"eslint-config-react-app": "^6.0.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-webpack-plugin": "^2.5.4",
"exifr": "^7.1.3",
"fast-exif": "^1.0.1",
"gatsby": "^5.0.1",
"gatsby-plugin-eslint": "^4.0.3",
"gatsby-plugin-image": "^3.0.0",
"gatsby-plugin-manifest": "^5.0.0",
"gatsby-plugin-mdx": "^5.0.0",
"gatsby-plugin-postcss": "^6.0.0",
"gatsby-plugin-preval": "^1.0.0",
"gatsby-plugin-react-helmet": "^6.0.0",
@ -58,7 +43,7 @@
"kebab-case": "^1.0.1",
"node-iptc": "^1.0.5",
"node-vibrant": "3.1.6",
"postcss": "^8.4.18",
"postcss": "^8.4.19",
"postcss-nested": "^6.0.0",
"ramda": "^0.27.1",
"react": "^18.2.0",
@ -67,7 +52,7 @@
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"sass": "^1.34.0",
"tailwindcss": "^3.2.0",
"tailwindcss": "^3.2.4",
"use-breakpoint": "^2.0.1"
},
"devDependencies": {
@ -79,7 +64,13 @@
"@types/react-helmet": "^6.1.5",
"@typescript-eslint/eslint-plugin": "^5.39.0",
"@typescript-eslint/parser": "^5.39.0",
"babel-plugin-preval": "^5.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.25.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-webpack-plugin": "^2.5.4",
"prettier": "2.3.2",
"typescript": "^4.8.4"
}

View File

@ -153,11 +153,15 @@ const GalleryImage = ({ data, location: { state } }) => {
<Nav
className="mb-4"
internalLinks={[
{ href: "/", label: "Home" },
{
href: getGalleryPageUrl({ keyword: filterKeyword, sortKey }, image.base),
href: getGalleryPageUrl(
{ keyword: filterKeyword, sortKey },
image.base
),
label: (
<>
Home <kbd className="font-normal">esc</kbd>
Gallery <kbd className="font-normal">esc</kbd>
</>
),
},

View File

@ -9,7 +9,9 @@ interface KeywordsPickerProps {
const KeywordsPicker = ({ keywords, value, onChange }: KeywordsPickerProps) => {
return (
<div className="mx-2 mt-2">
<span className="text-xs text-[#A2A2A2]">Collections</span>
<span className="text-xs text-[var(--spectrum-fieldlabel-text-color,var(--spectrum-alias-label-text-color))]">
Collections
</span>
<ul className="flex gap-1 flex-wrap mt-1 mb-2">
{keywords.map((keyword) => {
const selected = value === keyword;
@ -18,8 +20,14 @@ const KeywordsPicker = ({ keywords, value, onChange }: KeywordsPickerProps) => {
<button
className={classNames(
"transition",
"py-[5px] px-3 rounded-full text-[#C8C8C8] hover:bg-black bg-[#1A1A1A] border border-[#494949]",
selected && "bg-blue-600 hover:bg-blue-800"
`py-[5px] px-3 rounded-full`,
`text-[var(--spectrum-fieldbutton-text-color,var(--spectrum-alias-text-color))]
border border-[var(--spectrum-fieldbutton-border-color,var(--spectrum-alias-border-color))]`,
selected
? "bg-blue-500 hover:bg-blue-300"
: `bg-[var(--spectrum-fieldbutton-background-color,var(--spectrum-global-color-gray-75))]
hover:bg-[var(--spectrum-fieldbutton-background-color-down,var(--spectrum-global-color-gray-200))]`
)}
onClick={() => (selected ? onChange(null) : onChange(keyword))}
type="button"

View File

@ -42,27 +42,12 @@ const MasonryGallery = ({
() => R.pick(R.keys(aspectTargetsByBreakpoint), themeBreakpoints),
[aspectTargetsByBreakpoint]
);
console.log(
"🚀 ~ file: MasonryGallery.tsx ~ line 41 ~ breakpoints",
breakpoints
);
const { observe, width, currentBreakpoint } = useDimensions({
const { observe, currentBreakpoint } = useDimensions({
breakpoints,
});
const breakpoint = currentBreakpoint.length ? currentBreakpoint : "xs";
const containerWidth = width ? width : 320;
// console.log(
// "🚀 ~ file: MasonryGallery.tsx ~ line 47 ~ currentBreakpoint",
// currentBreakpoint
// );
// const { breakpoint } = useBreakpoint(breakpoints, "sm");
console.log(
"🚀 ~ file: MasonryGallery.tsx ~ line 46 ~ breakpoint",
breakpoint
);
const aspectRatios = React.useMemo(
() => R.map(getAspectRatio, images).filter(Boolean),
@ -118,7 +103,7 @@ const MasonryGallery = ({
<div
className={classNames(
"flex items-center flex-wrap mx-auto",
isClient ? "sm:container" : "max-w-[320px]"
isClient ? "" : "max-w-[320px]"
)}
ref={observe}
style={{
@ -134,10 +119,10 @@ const MasonryGallery = ({
const rowAspectRatioSum = currentRow.aspect;
const ar = getAspectRatio(image);
let width;
let height = `calc(${containerWidth}px / ${rowAspectRatioSum} - 10px)`;
let height = `calc(100vw / ${rowAspectRatioSum} - 10px)`;
if (rowAspectRatioSum < targetAspect * 0.66) {
// incomplete row, render stuff at "ideal" sizes instead of filling width
width = `calc(${containerWidth}px / ${targetAspect / ar})`;
width = `calc(100vw / ${targetAspect / ar})`;
height = "unset";
} else {
const widthNumber = ((ar / rowAspectRatioSum) * 100).toFixed(7);
@ -169,7 +154,7 @@ const MasonryGallery = ({
${image.fields?.imageMeta?.dominantHue?.[1] ?? 0 * 100}%,
${image.fields?.imageMeta?.dominantHue?.[2] ?? 0 * 100}%
)`
: "black",
: "white",
}}
to={`/photogallery/${image.base}`}
>

View File

@ -8,13 +8,11 @@ import Menu from "@spectrum-icons/workflow/Menu";
const navClasses =
"hover:underline hover:bg-transparentblack block p-3 text-vibrant-light";
const ExternalLinks = ({ isVertical }: { isVertical: boolean }) => (
const ExternalLinks = () => (
<ul
className={classnames(
"z-30 overflow-hidden",
isVertical
? "inline-flex flex-wrap justify-center bg-vibrant-dark rounded-xl"
: "absolute rounded-md top-[40px] border border-vibrant-light"
"z-30 overflow-hidden bg-vibrant-dark",
"absolute top-[40px] border border-vibrant-light"
)}
>
<li>
@ -80,21 +78,25 @@ interface NavProps {
}
const Nav = ({ internalLinks, className }: NavProps) => {
const { observe, currentBreakpoint } = useDimensions({
breakpoints: { XS: 0, LG: 750 },
updateOnBreakpointChange: true,
});
// const { observe, currentBreakpoint } = useDimensions({
// breakpoints: { XS: 0, LG: 750 },
// updateOnBreakpointChange: true,
// });
const [linksMenu, setLinksMenu] = useState(false);
return (
<nav
className={classnames(
"mt-0 flex justify-center w-full font-serif",
"mt-0 flex justify-between items-center w-full font-sans px-6",
className
)}
ref={observe}
// ref={observe}
style={{ zIndex: 100 }}
>
<div className="flex items-baseline">
<h1 className="font-bold mr-2">Chuck Dries</h1>
<h2>Software Engineer & Photographer</h2>
</div>
<div className="flex">
<ul className="inline-flex flex-wrap justify-center">
{internalLinks &&
@ -110,28 +112,21 @@ const Nav = ({ internalLinks, className }: NavProps) => {
</li>
))}
</ul>
{internalLinks && currentBreakpoint !== "XS" && (
<span className="block p-3 text-vibrant-light opacity-75">|</span>
)}
{currentBreakpoint === "XS" && (
<button
className={classnames(
"mx-2 hover:underline inline-flex align-middle items-center",
navClasses
)}
onClick={() => setLinksMenu(!linksMenu)}
>
<Menu
UNSAFE_className="mr-1"
aria-label="show external links"
size="S"
/>
Links
</button>
)}
{(currentBreakpoint !== "XS" || linksMenu) && (
<ExternalLinks isVertical={currentBreakpoint !== "XS"} />
)}
<button
className={classnames(
"hover:underline inline-flex align-middle items-center",
navClasses
)}
onClick={() => setLinksMenu(!linksMenu)}
>
{/* <Menu
UNSAFE_className="mr-1"
aria-label="show external links"
size="S"
/> */}
Links
</button>
{linksMenu && <ExternalLinks />}
</div>
</nav>
);

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

@ -1427,138 +1427,6 @@ type JSONQueryOperatorInput = {
readonly regex: InputMaybe<Scalars['JSON']>;
};
type Mdx = Node & {
readonly children: ReadonlyArray<Node>;
readonly excerpt: Maybe<Scalars['String']>;
readonly id: Scalars['ID'];
readonly internal: Internal;
readonly parent: Maybe<Node>;
readonly tableOfContents: Maybe<Scalars['JSON']>;
};
type Mdx_excerptArgs = {
pruneLength?: InputMaybe<Scalars['Int']>;
};
type Mdx_tableOfContentsArgs = {
maxDepth: InputMaybe<Scalars['Int']>;
};
type MdxConnection = {
readonly distinct: ReadonlyArray<Scalars['String']>;
readonly edges: ReadonlyArray<MdxEdge>;
readonly group: ReadonlyArray<MdxGroupConnection>;
readonly max: Maybe<Scalars['Float']>;
readonly min: Maybe<Scalars['Float']>;
readonly nodes: ReadonlyArray<Mdx>;
readonly pageInfo: PageInfo;
readonly sum: Maybe<Scalars['Float']>;
readonly totalCount: Scalars['Int'];
};
type MdxConnection_distinctArgs = {
field: MdxFieldSelector;
};
type MdxConnection_groupArgs = {
field: MdxFieldSelector;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
};
type MdxConnection_maxArgs = {
field: MdxFieldSelector;
};
type MdxConnection_minArgs = {
field: MdxFieldSelector;
};
type MdxConnection_sumArgs = {
field: MdxFieldSelector;
};
type MdxEdge = {
readonly next: Maybe<Mdx>;
readonly node: Mdx;
readonly previous: Maybe<Mdx>;
};
type MdxFieldSelector = {
readonly children: InputMaybe<NodeFieldSelector>;
readonly excerpt: InputMaybe<FieldSelectorEnum>;
readonly id: InputMaybe<FieldSelectorEnum>;
readonly internal: InputMaybe<InternalFieldSelector>;
readonly parent: InputMaybe<NodeFieldSelector>;
readonly tableOfContents: InputMaybe<FieldSelectorEnum>;
};
type MdxFilterInput = {
readonly children: InputMaybe<NodeFilterListInput>;
readonly excerpt: InputMaybe<StringQueryOperatorInput>;
readonly id: InputMaybe<StringQueryOperatorInput>;
readonly internal: InputMaybe<InternalFilterInput>;
readonly parent: InputMaybe<NodeFilterInput>;
readonly tableOfContents: InputMaybe<JSONQueryOperatorInput>;
};
type MdxGroupConnection = {
readonly distinct: ReadonlyArray<Scalars['String']>;
readonly edges: ReadonlyArray<MdxEdge>;
readonly field: Scalars['String'];
readonly fieldValue: Maybe<Scalars['String']>;
readonly group: ReadonlyArray<MdxGroupConnection>;
readonly max: Maybe<Scalars['Float']>;
readonly min: Maybe<Scalars['Float']>;
readonly nodes: ReadonlyArray<Mdx>;
readonly pageInfo: PageInfo;
readonly sum: Maybe<Scalars['Float']>;
readonly totalCount: Scalars['Int'];
};
type MdxGroupConnection_distinctArgs = {
field: MdxFieldSelector;
};
type MdxGroupConnection_groupArgs = {
field: MdxFieldSelector;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
};
type MdxGroupConnection_maxArgs = {
field: MdxFieldSelector;
};
type MdxGroupConnection_minArgs = {
field: MdxFieldSelector;
};
type MdxGroupConnection_sumArgs = {
field: MdxFieldSelector;
};
type MdxSortInput = {
readonly children: InputMaybe<NodeSortInput>;
readonly excerpt: InputMaybe<SortOrderEnum>;
readonly id: InputMaybe<SortOrderEnum>;
readonly internal: InputMaybe<InternalSortInput>;
readonly parent: InputMaybe<NodeSortInput>;
readonly tableOfContents: InputMaybe<SortOrderEnum>;
};
/** Node Interface */
type Node = {
readonly children: ReadonlyArray<Node>;
@ -1631,7 +1499,6 @@ type Query = {
readonly allDirectory: DirectoryConnection;
readonly allFile: FileConnection;
readonly allImageSharp: ImageSharpConnection;
readonly allMdx: MdxConnection;
readonly allSite: SiteConnection;
readonly allSiteBuildMetadata: SiteBuildMetadataConnection;
readonly allSiteFunction: SiteFunctionConnection;
@ -1640,7 +1507,6 @@ type Query = {
readonly directory: Maybe<Directory>;
readonly file: Maybe<File>;
readonly imageSharp: Maybe<ImageSharp>;
readonly mdx: Maybe<Mdx>;
readonly site: Maybe<Site>;
readonly siteBuildMetadata: Maybe<SiteBuildMetadata>;
readonly siteFunction: Maybe<SiteFunction>;
@ -1673,14 +1539,6 @@ type Query_allImageSharpArgs = {
};
type Query_allMdxArgs = {
filter: InputMaybe<MdxFilterInput>;
limit: InputMaybe<Scalars['Int']>;
skip: InputMaybe<Scalars['Int']>;
sort: InputMaybe<ReadonlyArray<InputMaybe<MdxSortInput>>>;
};
type Query_allSiteArgs = {
filter: InputMaybe<SiteFilterInput>;
limit: InputMaybe<Scalars['Int']>;
@ -1818,16 +1676,6 @@ type Query_imageSharpArgs = {
};
type Query_mdxArgs = {
children: InputMaybe<NodeFilterListInput>;
excerpt: InputMaybe<StringQueryOperatorInput>;
id: InputMaybe<StringQueryOperatorInput>;
internal: InputMaybe<InternalFilterInput>;
parent: InputMaybe<NodeFilterInput>;
tableOfContents: InputMaybe<JSONQueryOperatorInput>;
};
type Query_siteArgs = {
buildTime: InputMaybe<DateQueryOperatorInput>;
children: InputMaybe<NodeFilterListInput>;

View File

@ -71,38 +71,6 @@ const IndexPage = ({
}
}, [isClient, imageIndex, image, shuffleImage]);
// React.useEffect(() => {
// const keyListener = (e: KeyboardEvent) => {
// switch (e.code) {
// case "Space": {
// shuffleImage(image);
// return;
// }
// case "ArrowRight": {
// if (imageIndex === images.length - 1) {
// setImageIndex(0);
// return;
// }
// setImageIndex(imageIndex + 1);
// return;
// }
// case "ArrowLeft": {
// if (imageIndex === 0) {
// setImageIndex(images.length - 1);
// return;
// }
// setImageIndex(imageIndex - 1);
// return;
// }
// }
// };
// document.addEventListener("keydown", keyListener);
// return () => {
// document.removeEventListener("keydown", keyListener);
// };
// }, [imageIndex, images.length, image, shuffleImage]);
const browserIsLandscape = useMediaQuery("(orientation: landscape)");
const vibrant = getVibrant(image);
@ -120,137 +88,82 @@ const IndexPage = ({
<Helmet>
<title>Chuck Dries</title>
<body
className={classnames(isClient ? "bg-muted-dark" : "bg-gray-800")}
className="bg-white"
// @ts-ignore
style={getHelmetSafeBodyStyle(vibrant!, screenHeight)}
style={getHelmetSafeBodyStyle({
Muted: [0, 0, 0],
LightMuted: [0, 0, 0],
Vibrant: [0, 0, 0],
LightVibrant: [0, 0, 0],
DarkMuted: [255, 255, 255],
DarkVibrant: [255, 255, 255],
})}
/>
</Helmet>
<main
className={classnames(
"font-serif",
imageIsLandscape
? "landscape:grid portrait:h-actual-screen portrait:flex flex-col justify-around"
: "portrait:grid landscape:flex flex-row"
)}
>
<div
className={classnames(
"landscape:flex-auto flex flex-col items-center",
imageIsLandscape
? "portrait:items-center landscape:w-screen justify-between"
: "landscape:justify-center portrait:w-screen"
)}
style={{ gridArea: "1/1" }}
>
<Nav
internalLinks={[
{ href: "/", label: "Home" },
{ href: "/photogallery/", label: "Gallery" },
]}
/>
<div
className={classnames(
"flex flex-col",
!imageIsLandscape && "portrait:flex-auto "
)}
>
<div
className={classnames(
"rounded-[50px] p-3 md:p-5 ml-2 mr-4 md:ml-3 md:mr-5 flex flex-col items-center z-10 mb-3",
isClient
? imageIsLandscape
? "text-vibrant-light landscape:text-vibrant-dark landscape:cool-border-big landscape:border-r-[20px] landscape:border-b-[20px]"
: "text-vibrant-light portrait:text-vibrant-dark portrait:cool-border-big portrait:border-r-[20px] portrait:border-b-[20px]"
: "bg-gray-50 border-r-[20px] border-b-[20px]",
isClient && ""
)}
>
<h1
className={classnames(
"mb-0 mt-0 text-center font-black z-20 text-5xl sm:text-7xl md:text-8xl lg:text-9xl"
)}
style={{ lineHeight: "85%" }}
>
Chuck Dries
</h1>
<h2
className={classnames(
"p-3 text-center z-20 font-bold text-lg md:text-2xl lg:text-3xl"
)}
style={{ lineHeight: "110%" }}
>
Full Stack Software Engineer &amp; Photographer
</h2>
</div>
</div>
<div
className={classnames(
imageIsLandscape ? "block portrait:hidden" : ""
)}
>
<ActionButtons
image={image}
isClient={isClient}
shuffleImage={shuffleImage}
/>
</div>
</div>
{isClient && img ? (
<GatsbyImage
alt=""
className={classnames(
imageIsLandscape
? "landscape:h-actual-screen portrait:h-two-thirds-vw"
: "h-actual-screen portrait:w-full"
)}
image={img}
loading="eager"
style={{
gridArea: "1/1",
width:
browserIsLandscape && !imageIsLandscape
? `${ar * 100}vh`
: "100%",
}}
/>
) : (
<div
className="landscape:h-actual-screen portrait:h-two-thirds-vw w-full"
style={{ gridArea: "1/1" }}
></div>
)}
<main className="font-sans">
<Nav
internalLinks={[
{ href: "/", label: "Home" },
{ href: "/photogallery/", label: "Gallery" },
]}
/>
<GatsbyImage
alt=""
className="m-6 mt-0 max-h-[calc(100vh-77px)]"
// className={classnames(
// imageIsLandscape
// ? "landscape:h-actual-screen portrait:h-two-thirds-vw"
// : "h-actual-screen portrait:w-full"
// )}
image={img!}
loading="eager"
style={
{
// gridArea: "1/1",
// width:
// browserIsLandscape && !imageIsLandscape
// ? `${ar * 100}vh`
// : "100%",
}
}
/>
</main>
</>
);
};
export const query = graphql`query IndexPage {
allFile(
filter: {sourceInstanceName: {eq: "gallery"}, base: {in: ["DSC02615-2.jpg"]}}
sort: {fields: {imageMeta: {dateTaken: DESC}}}
) {
nodes {
relativePath
base
childImageSharp {
fluid {
aspectRatio
}
gatsbyImageData(
layout: FULL_WIDTH
placeholder: NONE
breakpoints: [750, 1080, 1366, 1920, 2560, 3840]
)
export const query = graphql`
query IndexPage {
allFile(
filter: {
sourceInstanceName: { eq: "gallery" }
base: { in: ["DSC02615-2.jpg"] }
}
fields {
imageMeta {
vibrant {
...VibrantColors
sort: { fields: { imageMeta: { dateTaken: DESC } } }
) {
nodes {
relativePath
base
childImageSharp {
fluid {
aspectRatio
}
gatsbyImageData(
# layout: FULL_WIDTH
placeholder: NONE
breakpoints: [750, 1080, 1366, 1920, 2560, 3840]
)
}
fields {
imageMeta {
vibrant {
...VibrantColors
}
}
}
}
}
}
}`;
`;
export default IndexPage;

View File

@ -163,15 +163,15 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
<Helmet>
<title>Photo Gallery | Chuck Dries</title>
<body
className="bg-black text-white"
className="bg-white"
// @ts-ignore
style={getHelmetSafeBodyStyle({
Muted: [255, 255, 255],
DarkMuted: [0, 0, 0],
LightMuted: [255, 255, 255],
Vibrant: [255, 255, 255],
LightVibrant: [231, 229, 228],
DarkVibrant: [0, 0, 0],
Muted: [0, 0, 0],
LightMuted: [0, 0, 0],
Vibrant: [0, 0, 0],
LightVibrant: [0, 0, 0],
DarkMuted: [255, 255, 255],
DarkVibrant: [255, 255, 255],
})}
/>
</Helmet>
@ -179,14 +179,13 @@ const GalleryPage = ({ data }: PageProps<Queries.GalleryPageQueryQuery>) => {
<div className="bg-vibrant-dark text-light-vibrant pb-1">
<Nav
className="mb-4"
internalLinks={[{ href: "/", label: "Home" }]}
internalLinks={[
{ href: "/", label: "Home" },
{ href: "/photogallery/", label: "Gallery" },
]}
/>
<div className="flex flex-col text-center mr-5 md:ml-4 ml-2 my-4 md:my-7 font-serif">
<h1 className="text-5xl mt-0 font-black z-10">Chuck Dries</h1>
<h2 className="">Full Stack Software Engineer & Photographer</h2>
</div>
</div>
<div className="flex flex-col md:flex-row md:items-end justify-between sm:container sm:mx-auto">
<div className="flex flex-col md:flex-row md:items-end justify-between px-6 sm:mx-auto">
<KeywordsPicker
keywords={[
"night",

4997
yarn.lock

File diff suppressed because it is too large Load Diff