finalize site 🎉

This commit is contained in:
Jack Merrill 2023-06-14 22:44:22 -05:00
parent 6b0efea07c
commit f4318dcda8
No known key found for this signature in database
GPG Key ID: B8E3CDF57DD80CA5
15 changed files with 307 additions and 112 deletions

1
.vercelignore Normal file
View File

@ -0,0 +1 @@
/src/app/internal

View File

@ -10,6 +10,7 @@
},
"dependencies": {
"@heroicons/react": "^2.0.18",
"@next/bundle-analyzer": "^13.4.5",
"@radix-ui/react-context-menu": "^2.1.3",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.4",

View File

@ -62,7 +62,7 @@ export default function ProjectModal({
<Dialog.Root open onOpenChange={handleOpenChange}>
<Dialog.Portal>
<Dialog.Overlay className="bg-zinc-900 opacity-75 data-[state=open]:animate-overlayShow fixed inset-0" />
<Dialog.Content className="data-[state=open]:animate-contentShow overflow-y-scroll fixed top-[50%] left-[50%] w-[90vw] max-h-[85vh] max-w-[50vw] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-white dark:bg-zinc-800 px-8 py-12 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none">
<Dialog.Content className="data-[state=open]:animate-contentShow overflow-y-scroll fixed top-[50%] left-[50%] w-[90vw] max-h-[85vh] md:max-w-[50vw] max-w-[90vw] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-white dark:bg-zinc-800 px-8 py-12 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none">
<Dialog.Title
className={cn(
"dark:text-white text-indigo-600 m-0 text-6xl font-bold",

View File

@ -6,19 +6,21 @@ import Link from "next/link";
export default async function Page() {
return (
<div className="grid grid-cols-5 gap-4 mx-auto max-w-7xl">
<div className="grid grid-cols-5 gap-4 px-4 mx-auto text-black max-w-7xl dark:text-white">
<div className="col-span-4 space-y-3">
<h1 className="font-black text-8xl">Hey! I&apos;m Jack Merrill.</h1>
<h1 className="text-4xl font-black md:text-8xl">
Hey! I&apos;m Jack Merrill.
</h1>
<p className="text-2xl">
<p className="text-xl md:text-2xl">
I&apos;m a software engineer, designer, and student from the United
States. I&apos;m working to bring accessible designs to the masses.
</p>
</div>
<div className="w-full h-full col-span-1 row-span-3 px-8 py-4 space-y-12 rounded-md bg-violet-500">
<div className="flex justify-center w-full">
<div className="h-auto p-12 border-2 border-white rounded-md">
<div className="grid order-last w-full h-full grid-cols-2 px-8 py-4 rounded-md lg:order-none lg:space-y-12 gap-x-2 lg:row-span-3 lg:grid-cols-1 lg:col-span-1 col-span-full bg-violet-500">
<div className="flex justify-center lg:w-full">
<div className="h-auto p-8 border-4 border-white aspect-square w-fit max-h-48 lg:p-12 md:p-10 sm:p-6 rounded-xl">
<Logo />
</div>
</div>
@ -27,9 +29,9 @@ export default async function Page() {
</div>
<div className="col-span-4 space-y-3">
<h2 className="text-6xl font-black">About Me</h2>
<h2 className="text-3xl font-black md:text-6xl">About Me</h2>
<p className="text-2xl">
<p className="text-xl md:text-2xl">
I&apos;m a Division II (sophomore) student at Hampshire College,
studying interaction design. I&apos;m also a full-stack web developer
at{" "}
@ -43,8 +45,6 @@ export default async function Page() {
</Link>
.
</p>
<p className="text-2xl"></p>
</div>
</div>
);

View File

@ -55,7 +55,7 @@ export default async function Page({
</div>
{/* the content */}
<article className="prose dark:prose-invert prose-zinc max-w-none lg:prose-xl">
<article className="mx-auto prose dark:prose-invert prose-zinc max-w-7xl lg:prose-xl">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw]}
@ -84,3 +84,13 @@ export default async function Page({
</div>
);
}
export async function generateStaticParams() {
const { query, schema } = q("*")
.filterByType("post")
.grabOne$("slug.current", q.string());
const slugs = schema.parse(await client.fetch(query));
return slugs.map((slug) => ({ params: { id: slug } }));
}

View File

@ -12,7 +12,11 @@
import { NextStudio } from "next-sanity/studio";
import config from "../../../../../sanity.config";
const isDev = process.env.NODE_ENV === "development" || !process.env.NODE_ENV;
const isDev =
process.env.NODE_ENV === "development" ||
!process.env.NODE_ENV ||
process.env.NEXT_PUBLIC_ENV === "development" ||
!process.env.NEXT_PUBLIC_ENV;
export default function StudioPage() {
return isDev ? <NextStudio config={config} /> : null;

View File

@ -32,15 +32,15 @@ export default async function RootLayout({
}) {
const { query: projectQuery, schema: projectSchema } = q("*")
.filterByType("project")
.slice(0, 3)
.order("publishedAt desc")
.grab$({
title: q.string(),
subtitle: q.string(),
slug: q.slug("slug"),
publishedAt: q.date(),
mainImage: q("mainImage").grabOne$("asset->url", q.string()),
});
mainImage: q("mainImage").grabOne$("asset->url", q.string().optional()),
})
.slice(0, 2);
const { query: blogQuery, schema: blogSchema } = q("*")
.filterByType("post")
@ -53,7 +53,8 @@ export default async function RootLayout({
categories: q("categories")
.filter()
.deref()
.grabOne$("title", q.string()),
.grabOne$("title", q.string())
.nullable(),
});
const latestThreeProjects = projectSchema.parse(
@ -74,13 +75,13 @@ export default async function RootLayout({
<main className="w-full min-h-full space-y-6">{children}</main>
<footer className="flex justify-center w-full py-8 bg-zinc-900">
<div className="flex items-center justify-between w-full max-w-7xl">
<p className="flex items-center space-x-1 text-lg text-center text-zinc-100">
<footer className="flex justify-center w-full py-8 dark:bg-zinc-900 bg-zinc-300">
<div className="flex flex-col items-center w-full px-4 space-y-2 md:flex-row md:justify-between max-w-7xl">
<p className="flex items-center space-x-1 text-lg text-center text-black dark:text-zinc-100">
Made with
<Twemoji
emoji="❤️"
className="w-5 h-5 mx-1 text-red-500 transition-all duration-150 hover:scale-110"
className="w-5 h-5 mx-1 text-red-500 hover:animate-heartbeat"
ext="svg"
/>
by Jack Merrill
@ -93,20 +94,20 @@ export default async function RootLayout({
: "dev"}
</p>
<div className="flex space-x-4">
<div className="flex space-x-4 text-black dark:text-zinc-100">
<Link
href="https://www.linkedin.com/in/jack-merrill-39aa7520b/"
target="_blank"
>
<LinkedInLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer text-zinc-100 hover:text-[#0a66c2]" />
<LinkedInLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer hover:text-[#0a66c2]" />
</Link>
<Link href="https://github.com/jackmerrill" target="_blank">
<GitHubLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer text-zinc-100 hover:text-pink-500" />
<GitHubLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer hover:text-pink-500" />
</Link>
<Link href="https://twitter.com/jack__merrill" target="_blank">
<TwitterLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer text-zinc-100 hover:text-[#1d9bf0]" />
<TwitterLogoIcon className="w-6 h-6 transition-colors duration-150 cursor-pointer hover:text-[#1d9bf0]" />
</Link>
</div>
</div>

View File

@ -15,7 +15,7 @@ import Image from "next/image";
export default function Home() {
return (
<>
<section className="flex items-center px-6 py-48 mx-auto h-2/3 max-w-7xl">
<section className="flex items-center px-6 py-48 mx-auto text-black dark:text-white h-2/3 max-w-7xl">
<div className="space-y-4">
<h1 className="flex items-center text-6xl font-bold gap-x-4">
<Twemoji
@ -38,15 +38,15 @@ export default function Home() {
</div>
</section>
<section className="px-6 py-28 bg-zinc-900">
<section className="px-6 py-28 dark:bg-zinc-900 bg-slate-100">
<div className="flex flex-col items-center mx-auto space-y-4 max-w-7xl">
<h2 className="text-4xl font-bold">What I do</h2>
<div className="grid grid-cols-4 gap-x-4">
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
<div className="grid gap-4 text-black md:grid-cols-2 lg:grid-cols-4 dark:text-zinc-100">
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 dark:bg-zinc-800 bg-slate-300">
<div></div>
<div className="space-y-2">
<FrameIcon className="w-12 h-12 transition-colors duration-150 text-zinc-100 group-hover:text-pink-500" />
<FrameIcon className="w-12 h-12 transition-colors duration-150 group-hover:text-pink-500" />
<h3 className="text-2xl font-semibold">UI Design</h3>
<p className="text-lg">
Designing interfaces and websites that are accessible, usable,
@ -55,10 +55,10 @@ export default function Home() {
</div>
</div>
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 dark:bg-zinc-800 bg-slate-300">
<div></div>
<div className="space-y-2">
<CodeIcon className="w-12 h-12 transition-colors duration-150 text-zinc-100 group-hover:text-teal-500" />{" "}
<CodeIcon className="w-12 h-12 transition-colors duration-150 group-hover:text-teal-500" />{" "}
<h3 className="text-2xl font-semibold">Development</h3>
<p className="text-lg">
Building websites and software that are fast, responsive, and
@ -67,10 +67,10 @@ export default function Home() {
</div>
</div>
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 dark:bg-zinc-800 bg-slate-300">
<div></div>
<div className="space-y-2">
<MagicWandIcon className="w-12 h-12 transition-colors duration-150 text-zinc-100 group-hover:text-indigo-500" />{" "}
<MagicWandIcon className="w-12 h-12 transition-colors duration-150 group-hover:text-indigo-500" />{" "}
<h3 className="text-2xl font-semibold">Creative</h3>
<p className="text-lg">
Creating stunning designs and illustrations that are unique
@ -79,10 +79,10 @@ export default function Home() {
</div>
</div>
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 dark:bg-zinc-800 bg-slate-300">
<div></div>
<div className="space-y-2">
<ScissorsIcon className="w-12 h-12 transition-colors duration-150 text-zinc-100 group-hover:text-green-500" />{" "}
<ScissorsIcon className="w-12 h-12 transition-colors duration-150 group-hover:text-green-500" />{" "}
<h3 className="text-2xl font-semibold">Other</h3>
<p className="text-lg">
I&apos;m always looking to learn new things and expand my
@ -95,8 +95,8 @@ export default function Home() {
</section>
<section className="px-6 py-28">
<div className="flex flex-col items-center mx-auto space-y-4 max-w-7xl">
<h2 className="text-4xl font-bold">
<div className="flex flex-col items-center mx-auto space-y-4 text-center max-w-7xl">
<h2 className="text-4xl font-bold text-black dark:text-zinc-100">
Tell me about your next project
</h2>

View File

@ -7,26 +7,25 @@ import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
export default async function Page({
params: { id: slug },
params: { id },
}: {
params: { id: string };
}) {
const { query: projectQuery, schema: projectSchema } = q("*")
.filterByType("project")
.filter(`slug.current == "${slug}"`)
.filter(`slug.current == "${id}"`)
.grab$({
title: q.string(),
subtitle: q.string(),
slug: q.slug("slug"),
publishedAt: q.date(),
content: q.string(),
mainImage: q("mainImage").grabOne$("asset->url", q.string()),
})
.slice(0, 1);
mainImage: q("mainImage").grabOne$("asset->url", q.string().optional()),
});
const project = projectSchema.parse(await client.fetch(projectQuery))[0];
const r = project.mainImage.match(/(?<width>\d+)x(?<height>\d+)/);
const r = project.mainImage?.match(/(?<width>\d+)x(?<height>\d+)/);
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
@ -44,6 +43,7 @@ export default async function Page({
</h2>
</div>
</div>
{project.mainImage && (
<Image
className="object-cover w-full h-full"
src={project.mainImage}
@ -51,11 +51,12 @@ export default async function Page({
width={parseInt(r?.groups?.width ?? "400")}
height={parseInt(r?.groups?.height ?? "400")}
/>
)}
</div>
</div>
{/* the content */}
<article className="prose dark:prose-invert prose-zinc max-w-none lg:prose-xl">
<article className="px-4 pb-12 mx-auto prose dark:prose-invert prose-zinc max-w-7xl lg:prose-xl">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw]}
@ -84,3 +85,17 @@ export default async function Page({
</div>
);
}
export async function generateStaticParams() {
const { query: projectQuery, schema: projectSchema } = q("*")
.filterByType("project")
.grabOne$("slug.current", q.string());
const projects = projectSchema.parse(await client.fetch(projectQuery));
return projects.map((project) => ({
params: {
slug: project,
},
}));
}

View File

@ -13,7 +13,7 @@ export default async function Page() {
subtitle: q.string(),
slug: q.slug("slug"),
publishedAt: q.date(),
mainImage: q("mainImage").grabOne$("asset->url", q.string()),
mainImage: q("mainImage").grabOne$("asset->url", q.string().optional()),
categories: q("categories")
.filter()
.deref()
@ -24,7 +24,7 @@ export default async function Page() {
return (
<div>
<section className="flex items-center px-6 py-48 mx-auto h-2/3 max-w-7xl">
<section className="flex items-center px-6 py-48 mx-auto text-black dark:text-white h-2/3 max-w-7xl">
<div className="space-y-4">
<h1 className="flex items-center text-6xl font-bold gap-x-4">
<Twemoji emoji="🛠" ext="svg" /> Projects
@ -35,39 +35,45 @@ export default async function Page() {
</div>
</section>
<div className="dark:bg-zinc-900">
<section className="grid grid-cols-4 gap-4 py-8 mx-auto max-w-7xl">
<div className="dark:bg-zinc-900 bg-slate-200">
<section className="grid gap-4 px-4 py-8 mx-auto md:grid-cols-4 max-w-7xl">
{projects.map((project) => {
const r = project.mainImage.match(/(?<width>\d+)x(?<height>\d+)/);
const r = project.mainImage?.match(/(?<width>\d+)x(?<height>\d+)/);
return (
<Link
key={project.slug}
className="flex flex-col items-center justify-center p-6 space-y-4 transition-all duration-150 rounded-md dark:bg-zinc-800 hover:scale-105"
className="flex flex-col items-center justify-center h-full p-6 space-y-4 text-black transition-all duration-150 rounded-md dark:text-white dark:bg-zinc-800 bg-slate-300 hover:scale-105"
href={`/projects/${project.slug}`}
>
<div>
{project.mainImage && (
<Image
src={project.mainImage}
alt={project.title}
width={parseInt(r?.groups?.width ?? "400")}
height={parseInt(r?.groups?.height ?? "400")}
/>
)}
<h3 className="text-xl font-semibold">{project.title}</h3>
<p className="text-lg">{project.subtitle}</p>
</div>
<p className="text-md text-zinc-400">
Categories:
<p className="flex-grow">
<div className="flex flex-wrap flex-grow gap-1 text-md dark:text-zinc-400 text-slate-600">
<span className="w-full">Categories:</span>
{project.categories.map((category) => (
<span
key={category}
className="px-2 py-1 ml-2 text-sm font-semibold text-white bg-indigo-500 rounded-md"
className="px-2 py-1 text-sm font-semibold text-white bg-indigo-500 rounded-md"
>
{category}
</span>
))}
</div>
</p>
<div className="flex items-center space-x-2">
<div className="flex items-center mt-auto space-x-2">
<time
className="text-sm text-gray-500"
dateTime={project.publishedAt.toISOString()}

View File

@ -2,8 +2,8 @@
import { CopyIcon } from "@radix-ui/react-icons";
import { CopyCheckIcon } from "lucide-react";
import React, { useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import React, { useEffect, useState } from "react";
import { PrismAsync as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
const CodeBlock = ({
@ -32,6 +32,7 @@ const CodeBlock = ({
};
const match = /language-(\w+)/.exec(className || "");
return !inline && match ? (
<div className="relative">
<SyntaxHighlighter

View File

@ -13,7 +13,12 @@ import {
} from "./ui/context-menu";
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
import { cn } from "@/lib/utils";
import { BackpackIcon, Pencil2Icon } from "@radix-ui/react-icons";
import {
ArrowRightIcon,
BackpackIcon,
Pencil2Icon,
} from "@radix-ui/react-icons";
import { ContextMenuSeparator } from "@radix-ui/react-context-menu";
export default function Navbar({
projects,
@ -24,40 +29,73 @@ export default function Navbar({
title: string;
subtitle: string;
slug: string;
mainImage: string;
mainImage?: string;
}[];
blogPosts: {
publishedAt: Date;
title: string;
slug: string;
categories: string[];
categories?: string[] | null;
}[];
}) {
return (
<div className="flex items-center w-full p-6 mx-auto max-w-7xl">
<div className="flex items-center justify-between w-full p-6 mx-auto md:justify-normal max-w-7xl">
<ContextMenu>
<ContextMenuTrigger>
<Link href="/">
<div className="p-4 bg-gray-800 rounded-md w-14 h-14 animate-rainbow-outline">
<Logo />
</div>
</Link>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>
<Link href="/">Home</Link>
<ContextMenuItem asChild>
<Link href="/" className="cursor-pointer">
Home
</Link>
</ContextMenuItem>
<ContextMenuItem asChild>
<Link href="/projects" className="cursor-pointer">
Projects
</Link>
</ContextMenuItem>
<ContextMenuItem asChild>
<Link href="/blog" className="cursor-pointer">
Blog
</Link>
</ContextMenuItem>
<ContextMenuItem asChild>
<Link href="/about" className="cursor-pointer">
About
</Link>
</ContextMenuItem>
<ContextMenuSeparator className="h-[1px] dark:bg-gray-600 m-[5px]" />
<ContextMenuItem asChild>
<Link
href="mailto:contact@jackmerrill.com"
className="cursor-pointer"
>
Contact
</Link>
</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
<div className="flex items-center flex-grow min-h-full px-4">
<div className="flex items-center min-h-full md:px-4 md:flex-grow">
<NavigationMenu.Root className="relative z-[1] mx-auto w-full flex h-full justify-center font-bold ">
<NavigationMenu.List className="flex m-0 list-none transition-all duration-150 rounded-full center text-slate-900 dark:text-white bg-slate-300 dark:bg-gray-800 hover:px-2">
<NavigationMenu.List className="flex m-0 list-none transition-all duration-150 rounded-full center text-slate-900 dark:text-white bg-slate-300 dark:bg-gray-800 md:hover:px-2">
<NavigationMenu.Item>
<NavigationMenu.Trigger className="hover:bg-gray-700 group flex select-none items-center justify-between gap-[2px] rounded-full h-full px-3 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]">
<NavigationMenu.Trigger className="dark:hover:bg-gray-700 hover:bg-slate-400 group flex select-none items-center justify-between gap-[2px] rounded-full h-full px-3 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]">
Projects
</NavigationMenu.Trigger>
<NavigationMenu.Content className="data-[motion=from-start]:animate-enterFromLeft data-[motion=from-end]:animate-enterFromRight data-[motion=to-start]:animate-exitToLeft data-[motion=to-end]:animate-exitToRight absolute top-0 left-0 w-full sm:w-auto">
<ul className="m-0 grid list-none gap-x-[10px] p-[22px] sm:w-[500px] sm:grid-cols-5">
<li className="grid col-span-2 row-span-3">
<ul className="m-0 grid list-none gap-[10px] p-[22px] sm:w-[500px] sm:grid-cols-5">
<li className="hidden col-span-2 row-span-3 md:grid">
<NavigationMenu.Link asChild>
<Link
className="focus:shadow-purple-500 from-purple-500 to-indigo-500 flex
@ -79,13 +117,13 @@ export default function Navbar({
{projects.map((project) => (
<li
key={project.slug}
className="col-span-3 transition duration-150 rounded-md hover:bg-gray-900"
className="col-span-3 text-black transition duration-150 rounded-md dark:hover:bg-gray-900 hover:bg-slate-400 dark:text-white"
>
<NavigationMenu.Link asChild>
<Link
href={`/projects/${project.slug}`}
className={
"focus:shadow-[0_0_0_2px] grid grid-cols-4 items-center focus:shadow-violet7 hover:bg-mauve3 select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
"focus:shadow-[0_0_0_2px] grid md:grid-cols-4 items-center focus:shadow-violet7 hover:bg-mauve3 select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
}
>
<div className="col-span-3">
@ -99,7 +137,7 @@ export default function Navbar({
{/* project image */}
{project.mainImage && (
<div className="relative w-full h-full overflow-hidden rounded-md">
<div className="relative hidden w-full h-full overflow-hidden rounded-md md:block">
<Image
src={project.mainImage}
alt=""
@ -113,17 +151,34 @@ export default function Navbar({
</NavigationMenu.Link>
</li>
))}
<li className="col-span-3 text-black transition duration-150 rounded-md md:hidden dark:hover:bg-gray-900 hover:bg-slate-400 dark:text-white">
<NavigationMenu.Link asChild>
<Link
href="/projects"
className={
"focus:shadow-[0_0_0_2px] flex items-center justify-between focus:shadow-violet7 hover:bg-mauve3 select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
}
>
<p className="font-bold leading-[1.2]">
See all projects
</p>
<ArrowRightIcon className="w-5 h-5" />
</Link>
</NavigationMenu.Link>
</li>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger className="hover:bg-gray-700 h-full group flex select-none items-center justify-between gap-[2px] rounded-full px-3 py-2 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]">
<NavigationMenu.Trigger className="dark:hover:bg-gray-700 hover:bg-slate-400 h-full group flex select-none items-center justify-between gap-[2px] rounded-full px-3 py-2 text-[15px] font-medium leading-none outline-none focus:shadow-[0_0_0_2px]">
Blog
</NavigationMenu.Trigger>
<NavigationMenu.Content className="data-[motion=from-start]:animate-enterFromLeft data-[motion=from-end]:animate-enterFromRight data-[motion=to-start]:animate-exitToLeft data-[motion=to-end]:animate-exitToRight absolute top-0 left-0 w-full sm:w-auto">
<ul className="m-0 grid list-none gap-x-[10px] p-[22px] sm:w-[500px] sm:grid-cols-5">
<li className="grid col-span-2 row-span-3">
<ul className="m-0 grid list-none gap-[10px] p-[22px] sm:w-[500px] sm:grid-cols-5">
<li className="hidden col-span-2 row-span-3 md:grid">
<NavigationMenu.Link asChild>
<Link
className="focus:shadow-green-500 from-green-500 to-cyan-500 flex
@ -144,7 +199,7 @@ export default function Navbar({
{blogPosts.map((post) => (
<li
key={post.slug}
className="col-span-3 transition duration-150 rounded-md hover:bg-gray-900"
className="col-span-3 text-black transition duration-150 rounded-md dark:hover:bg-gray-900 hover:bg-slate-400 dark:text-white"
>
<NavigationMenu.Link asChild>
<Link
@ -156,20 +211,39 @@ export default function Navbar({
<div className="mb-[5px] font-bold leading-[1.2]">
{post.title}
</div>
{post.categories && post.categories.length > 0 && (
<p className="font-medium leading-[1.4]">
Categories: {post.categories.join(", ")}
</p>
)}
</Link>
</NavigationMenu.Link>
</li>
))}
<li className="col-span-3 text-black transition duration-150 rounded-md md:hidden dark:hover:bg-gray-900 hover:bg-slate-400 dark:text-white">
<NavigationMenu.Link asChild>
<Link
href="/blog"
className={
"focus:shadow-[0_0_0_2px] flex items-center justify-between focus:shadow-violet7 hover:bg-mauve3 select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
}
>
<p className="font-bold leading-[1.2]">
See all blog posts
</p>
<ArrowRightIcon className="w-5 h-5" />
</Link>
</NavigationMenu.Link>
</li>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link
className="hover:bg-gray-700 h-full items-center flex select-none rounded-full px-3 py-2 text-[15px] font-medium leading-none no-underline outline-none focus:shadow-[0_0_0_2px]"
className="dark:hover:bg-gray-700 hover:bg-slate-400 h-full items-center flex select-none rounded-full px-3 py-2 text-[15px] font-medium leading-none no-underline outline-none focus:shadow-[0_0_0_2px]"
asChild
>
<Link href="/about">About</Link>
@ -191,7 +265,7 @@ export default function Navbar({
</NavigationMenu.Root>
</div>
<div className="flex items-center">
<div className="items-center hidden md:flex">
<Button link rainbow href="mailto:contact@jackmerrill.com">
Contact
</Button>

View File

@ -6,14 +6,17 @@ import * as Tooltip from "@radix-ui/react-tooltip";
export default function SidecardList() {
return (
<Tooltip.Provider>
<ul className="flex flex-col gap-4 mt-4">
<ul className="flex flex-col justify-center gap-4 lg:mt-4">
<Tooltip.Root>
<Tooltip.Trigger asChild>
<li className="flex items-center gap-2 w-min">
<PersonIcon className="w-6 h-6" />
<span className="ml-2 font-semibold text-md">
<span className="sr-only">Age</span>
{new Date().getFullYear() - 2004}
{Math.floor(
(new Date().getTime() - new Date(2004, 7, 13).getTime()) /
31557600000
)}
</span>
</li>
</Tooltip.Trigger>
@ -43,11 +46,11 @@ export default function SidecardList() {
<Tooltip.Root>
<Tooltip.Trigger asChild>
<li className="flex items-center w-full gap-2">
<li className="flex items-center gap-2 w-min min-w-fit">
<Crosshair2Icon className="w-6 h-6" />
<span className="ml-2 font-semibold text-md">
<span className="sr-only">Location</span>
Chicago, IL / Amherst, MA
Chicago, IL
</span>
</li>
</Tooltip.Trigger>

View File

@ -128,6 +128,11 @@ module.exports = {
from: { opacity: 0, transform: "translateX(-2px)" },
to: { opacity: 1, transform: "translateX(0)" },
},
heartbeat: {
"0%": { transform: "scale(1)" },
"50%": { transform: "scale(1.05)" },
"100%": { transform: "scale(1)" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
@ -148,6 +153,7 @@ module.exports = {
slideUpAndFade: "slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)",
slideRightAndFade:
"slideRightAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)",
heartbeat: "heartbeat 1s ease-in-out infinite",
},
},
},

View File

@ -812,6 +812,13 @@
dependencies:
"@lezer/common" "^1.0.0"
"@next/bundle-analyzer@^13.4.5":
version "13.4.5"
resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-13.4.5.tgz#19877dea00c829b0a23a189d821591bd49e0bbfb"
integrity sha512-jrjJ/m7YHqYDuLSXaAWv6eUEgH0gTSFaNCLRxnO6wSJODNV6BMbfYZsa5RJFVGzApPHj4DTPrz0rxn/9flIAXA==
dependencies:
webpack-bundle-analyzer "4.7.0"
"@next/env@13.4.3":
version "13.4.3"
resolved "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz"
@ -902,6 +909,11 @@
picocolors "^1.0.0"
tslib "^2.5.0"
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.21"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@portabletext/react@^1.0.6":
version "1.0.6"
resolved "https://registry.npmjs.org/@portabletext/react/-/react-1.0.6.tgz"
@ -2144,7 +2156,7 @@ acorn-walk@^7.0.0:
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn-walk@^8.0.2:
acorn-walk@^8.0.0, acorn-walk@^8.0.2:
version "8.2.0"
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
@ -2154,7 +2166,7 @@ acorn@^7.0.0:
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.1.0, acorn@^8.8.0, acorn@^8.8.1:
acorn@^8.0.4, acorn@^8.1.0, acorn@^8.8.0, acorn@^8.8.1:
version "8.8.2"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
@ -2565,7 +2577,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
"chalk@^3.0.0 || ^4.0.0", chalk@^4.0.0, chalk@^4.1.2:
"chalk@^3.0.0 || ^4.0.0", chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@ -2741,6 +2753,11 @@ commander@^5.0.0:
resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
commander@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
compress-commons@^4.1.0:
version "4.1.1"
resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz"
@ -3157,6 +3174,11 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
duplexer@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
duplexify@^3.5.0, duplexify@^3.6.0:
version "3.7.1"
resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz"
@ -4161,6 +4183,13 @@ gunzip-maybe@^1.4.1:
pumpify "^1.3.3"
through2 "^2.0.3"
gzip-size@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
dependencies:
duplexer "^0.1.2"
has-bigints@^1.0.1, has-bigints@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz"
@ -5597,6 +5626,11 @@ mri@^1.1.0:
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
mrmime@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
@ -5867,6 +5901,11 @@ open@^9.1.0:
is-inside-container "^1.0.0"
is-wsl "^2.2.0"
opener@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
optionator@^0.8.1:
version "0.8.3"
resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz"
@ -7021,6 +7060,15 @@ simple-wcswidth@^1.0.1:
resolved "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.0.1.tgz"
integrity sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==
sirv@^1.0.7:
version "1.0.19"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49"
integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==
dependencies:
"@polka/url" "^1.0.0-next.20"
mrmime "^1.0.0"
totalist "^1.0.0"
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
@ -7504,6 +7552,11 @@ toggle-selection@^1.0.6:
resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz"
integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==
totalist@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
tough-cookie@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz"
@ -7898,6 +7951,21 @@ webidl-conversions@^7.0.0:
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz"
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
webpack-bundle-analyzer@4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz#33c1c485a7fcae8627c547b5c3328b46de733c66"
integrity sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==
dependencies:
acorn "^8.0.4"
acorn-walk "^8.0.0"
chalk "^4.1.0"
commander "^7.2.0"
gzip-size "^6.0.0"
lodash "^4.17.20"
opener "^1.5.2"
sirv "^1.0.7"
ws "^7.3.1"
whatwg-encoding@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz"
@ -7987,6 +8055,11 @@ write-file-atomic@^3.0.0:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
ws@^7.3.1:
version "7.5.9"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
ws@^8.11.0:
version "8.13.0"
resolved "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz"