finish landing page
This commit is contained in:
parent
5ee230ba5f
commit
111af349a1
|
@ -12,6 +12,7 @@
|
||||||
"@heroicons/react": "^2.0.18",
|
"@heroicons/react": "^2.0.18",
|
||||||
"@radix-ui/react-context-menu": "^2.1.3",
|
"@radix-ui/react-context-menu": "^2.1.3",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
"@radix-ui/react-dropdown-menu": "^2.0.4",
|
||||||
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-navigation-menu": "^1.1.2",
|
"@radix-ui/react-navigation-menu": "^1.1.2",
|
||||||
"@sanity/image-url": "^1.0.2",
|
"@sanity/image-url": "^1.0.2",
|
||||||
"@sanity/vision": "^3.11.2",
|
"@sanity/vision": "^3.11.2",
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"eslint": "8.41.0",
|
"eslint": "8.41.0",
|
||||||
"eslint-config-next": "13.4.3",
|
"eslint-config-next": "13.4.3",
|
||||||
|
"groqd": "^0.15.6",
|
||||||
"lucide-react": "^0.220.0",
|
"lucide-react": "^0.220.0",
|
||||||
"next": "13.4.3",
|
"next": "13.4.3",
|
||||||
"next-sanity": "^4.3.3",
|
"next-sanity": "^4.3.3",
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
export const apiVersion =
|
export const apiVersion =
|
||||||
process.env.NEXT_PUBLIC_SANITY_API_VERSION || '2023-05-25'
|
process.env.NEXT_PUBLIC_SANITY_API_VERSION || "2023-05-25";
|
||||||
|
|
||||||
export const dataset = assertValue(
|
export const dataset = assertValue(
|
||||||
process.env.NEXT_PUBLIC_SANITY_DATASET,
|
process.env.NEXT_PUBLIC_SANITY_DATASET,
|
||||||
'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET'
|
"Missing environment variable: NEXT_PUBLIC_SANITY_DATASET"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const projectId = assertValue(
|
export const projectId = assertValue(
|
||||||
process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
|
process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
|
||||||
'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID'
|
"Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID"
|
||||||
)
|
);
|
||||||
|
|
||||||
export const useCdn = false
|
export const useCdn = false;
|
||||||
|
|
||||||
function assertValue<T>(v: T | undefined, errorMessage: string): T {
|
function assertValue<T>(v: T | undefined, errorMessage: string): T {
|
||||||
if (v === undefined) {
|
if (v === undefined) {
|
||||||
throw new Error(errorMessage)
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,48 @@
|
||||||
import {defineField, defineType} from 'sanity'
|
import { defineField, defineType } from "sanity";
|
||||||
|
|
||||||
export default defineType({
|
export default defineType({
|
||||||
name: 'author',
|
name: "author",
|
||||||
title: 'Author',
|
title: "Author",
|
||||||
type: 'document',
|
type: "document",
|
||||||
fields: [
|
fields: [
|
||||||
defineField({
|
defineField({
|
||||||
name: 'name',
|
name: "name",
|
||||||
title: 'Name',
|
title: "Name",
|
||||||
type: 'string',
|
type: "string",
|
||||||
}),
|
}),
|
||||||
defineField({
|
defineField({
|
||||||
name: 'slug',
|
name: "slug",
|
||||||
title: 'Slug',
|
title: "Slug",
|
||||||
type: 'slug',
|
type: "slug",
|
||||||
options: {
|
options: {
|
||||||
source: 'name',
|
source: "name",
|
||||||
maxLength: 96,
|
maxLength: 96,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
defineField({
|
defineField({
|
||||||
name: 'image',
|
name: "image",
|
||||||
title: 'Image',
|
title: "Image",
|
||||||
type: 'image',
|
type: "image",
|
||||||
options: {
|
options: {
|
||||||
hotspot: true,
|
hotspot: true,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'alt',
|
name: "alt",
|
||||||
type: 'string',
|
type: "string",
|
||||||
title: 'Alternative Text',
|
title: "Alternative Text",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
defineField({
|
defineField({
|
||||||
name: 'bio',
|
name: "bio",
|
||||||
title: 'Bio',
|
title: "Bio",
|
||||||
type: 'array',
|
type: "array",
|
||||||
of: [
|
of: [
|
||||||
{
|
{
|
||||||
title: 'Block',
|
title: "Block",
|
||||||
type: 'block',
|
type: "block",
|
||||||
styles: [{title: 'Normal', value: 'normal'}],
|
styles: [{ title: "Normal", value: "normal" }],
|
||||||
lists: [],
|
lists: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -50,8 +50,8 @@ export default defineType({
|
||||||
],
|
],
|
||||||
preview: {
|
preview: {
|
||||||
select: {
|
select: {
|
||||||
title: 'name',
|
title: "name",
|
||||||
media: 'image',
|
media: "image",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
|
@ -3,6 +3,15 @@ import { Inter } from "next/font/google";
|
||||||
import Background from "@/components/Background";
|
import Background from "@/components/Background";
|
||||||
import Navbar from "@/components/Navbar";
|
import Navbar from "@/components/Navbar";
|
||||||
import { client } from "../../sanity/lib/client";
|
import { client } from "../../sanity/lib/client";
|
||||||
|
import type ProjectType from "../../sanity/schemas/project";
|
||||||
|
import { q } from "groqd";
|
||||||
|
import Link from "next/link";
|
||||||
|
import {
|
||||||
|
GitHubLogoIcon,
|
||||||
|
LinkedInLogoIcon,
|
||||||
|
TwitterLogoIcon,
|
||||||
|
} from "@radix-ui/react-icons";
|
||||||
|
import Twemoji from "@/components/Twemoji";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
|
@ -17,20 +26,83 @@ export default async function RootLayout({
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const latestThreeProjects = await client.fetch(
|
const { query: projectQuery, schema: projectSchema } = q("*")
|
||||||
`*[_type == "project"] | order(_createdAt desc) [0...3]`
|
.filterByType("project")
|
||||||
|
.slice(0, 3)
|
||||||
|
.order("publishedAt desc")
|
||||||
|
.grab$({
|
||||||
|
title: q.string(),
|
||||||
|
subtitle: q.string(),
|
||||||
|
slug: q.slug("slug"),
|
||||||
|
publishedAt: q.date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { query: blogQuery, schema: blogSchema } = q("*")
|
||||||
|
.filterByType("post")
|
||||||
|
.slice(0, 3)
|
||||||
|
.order("publishedAt desc")
|
||||||
|
.grab$({
|
||||||
|
title: q.string(),
|
||||||
|
slug: q.slug("slug"),
|
||||||
|
publishedAt: q.date(),
|
||||||
|
categories: q("categories")
|
||||||
|
.filter()
|
||||||
|
.deref()
|
||||||
|
.grabOne$("title", q.string()),
|
||||||
|
});
|
||||||
|
|
||||||
|
const latestThreeProjects = projectSchema.parse(
|
||||||
|
await client.fetch(projectQuery)
|
||||||
);
|
);
|
||||||
console.log(latestThreeProjects);
|
|
||||||
|
const latestThreeBlogPosts = blogSchema.parse(await client.fetch(blogQuery));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" className="dark">
|
<html lang="en" className="dark">
|
||||||
<body
|
<body
|
||||||
className={`${inter.className} min-h-[100vh] flex justify-between flex-col bg-white heropattern-wiggle-indigo-100 dark:bg-black dark:heropattern-wiggle-slate-900`}
|
className={`${inter.className} min-h-[100vh] flex justify-between flex-col bg-white heropattern-wiggle-indigo-100 dark:bg-zinc-900 dark:heropattern-wiggle-zinc-800`}
|
||||||
>
|
>
|
||||||
<Navbar projects={latestThreeProjects} blogPosts={{}} />
|
<Navbar
|
||||||
|
projects={latestThreeProjects}
|
||||||
|
blogPosts={latestThreeBlogPosts}
|
||||||
|
/>
|
||||||
|
|
||||||
<main className="w-full min-h-full">{children}</main>
|
<main className="w-full min-h-full space-y-6">{children}</main>
|
||||||
|
|
||||||
<footer></footer>
|
<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">
|
||||||
|
Made with
|
||||||
|
<Twemoji
|
||||||
|
emoji="❤️"
|
||||||
|
className="w-5 h-5 mx-1 text-red-500 transition-all duration-150 hover:scale-110"
|
||||||
|
ext="svg"
|
||||||
|
/>
|
||||||
|
by Jack Merrill
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p className="text-xs font-light text-zinc-700">
|
||||||
|
Build {process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA || "dev"}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex space-x-4">
|
||||||
|
<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]" />
|
||||||
|
</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" />
|
||||||
|
</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]" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|
116
src/app/page.tsx
116
src/app/page.tsx
|
@ -2,27 +2,111 @@ import Background from "@/components/Background";
|
||||||
import Button from "@/components/Button";
|
import Button from "@/components/Button";
|
||||||
import Navbar from "@/components/Navbar";
|
import Navbar from "@/components/Navbar";
|
||||||
import Twemoji from "@/components/Twemoji";
|
import Twemoji from "@/components/Twemoji";
|
||||||
|
import {
|
||||||
|
CodeIcon,
|
||||||
|
CubeIcon,
|
||||||
|
FrameIcon,
|
||||||
|
HobbyKnifeIcon,
|
||||||
|
MagicWandIcon,
|
||||||
|
ScissorsIcon,
|
||||||
|
} from "@radix-ui/react-icons";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<section className="flex items-center px-6 mx-auto h-2/3 max-w-7xl">
|
<>
|
||||||
<div className="space-y-2 ">
|
<section className="flex items-center px-6 py-48 mx-auto h-2/3 max-w-7xl">
|
||||||
<h1 className="flex items-center text-6xl font-bold gap-x-2">
|
<div className="space-y-4">
|
||||||
<Twemoji emoji="👋" ext="svg" className="animate-hand-wave" /> Hey
|
<h1 className="flex items-center text-6xl font-bold gap-x-4">
|
||||||
hey!
|
<Twemoji
|
||||||
</h1>
|
emoji="👋"
|
||||||
<h2 className="text-2xl font-semibold">
|
ext="svg"
|
||||||
I'm Jack Merrill, a web designer and developer working to bring
|
className="motion-safe:animate-hand-wave"
|
||||||
accessible designs to the masses.
|
/>{" "}
|
||||||
</h2>
|
Hey hey!
|
||||||
|
</h1>
|
||||||
|
<h2 className="text-2xl font-semibold">
|
||||||
|
I'm Jack Merrill, a web designer and developer working to bring
|
||||||
|
accessible designs to the masses.
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<Button link href="mailto:contact@jackmerrill.com">
|
<Button link href="mailto:contact@jackmerrill.com">
|
||||||
Contact me
|
Contact me
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</section>
|
|
||||||
|
<section className="px-6 py-28 bg-zinc-900">
|
||||||
|
<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></div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<FrameIcon className="w-12 h-12 transition-colors duration-150 text-zinc-100 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,
|
||||||
|
and intuitive.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
|
||||||
|
<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" />{" "}
|
||||||
|
<h3 className="text-2xl font-semibold">Development</h3>
|
||||||
|
<p className="text-lg">
|
||||||
|
Building websites and software that are fast, responsive, and
|
||||||
|
accessible.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
|
||||||
|
<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" />{" "}
|
||||||
|
<h3 className="text-2xl font-semibold">Creative</h3>
|
||||||
|
<p className="text-lg">
|
||||||
|
Creating stunning designs and illustrations that are unique
|
||||||
|
and memorable.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid items-center grid-rows-2 p-4 group gap-y-2 bg-zinc-800">
|
||||||
|
<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" />{" "}
|
||||||
|
<h3 className="text-2xl font-semibold">Other</h3>
|
||||||
|
<p className="text-lg">
|
||||||
|
I'm always looking to learn new things and expand my
|
||||||
|
skillset. Check out my projects for more.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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">
|
||||||
|
Tell me about your next project
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="flex">
|
||||||
|
<Button rainbow link href="mailto:contact@jackmerrill.com">
|
||||||
|
Reach out
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,16 +12,28 @@ import {
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
} from "./ui/context-menu";
|
} from "./ui/context-menu";
|
||||||
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
|
import * as NavigationMenu from "@radix-ui/react-navigation-menu";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { BackpackIcon, Pencil2Icon } from "@radix-ui/react-icons";
|
||||||
|
|
||||||
export default function Navbar({
|
export default function Navbar({
|
||||||
projects,
|
projects,
|
||||||
blogPosts,
|
blogPosts,
|
||||||
}: {
|
}: {
|
||||||
projects: any;
|
projects: {
|
||||||
blogPosts: any;
|
publishedAt: Date;
|
||||||
|
title: string;
|
||||||
|
subtitle: string;
|
||||||
|
slug: string;
|
||||||
|
}[];
|
||||||
|
blogPosts: {
|
||||||
|
publishedAt: Date;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
categories: string[];
|
||||||
|
}[];
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between w-full p-6 mx-auto max-w-7xl">
|
<div className="flex items-center w-full p-6 mx-auto max-w-7xl">
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<ContextMenuTrigger>
|
<ContextMenuTrigger>
|
||||||
<div className="p-4 bg-gray-800 rounded-md w-14 h-14 animate-rainbow-outline">
|
<div className="p-4 bg-gray-800 rounded-md w-14 h-14 animate-rainbow-outline">
|
||||||
|
@ -35,42 +47,61 @@ export default function Navbar({
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|
||||||
<div className="flex items-center min-h-full font-bold transition-all duration-150 rounded-full text-slate-900 dark:text-white bg-slate-300 dark:bg-gray-800 hover:px-2">
|
<div className="flex items-center flex-grow min-h-full px-4">
|
||||||
<NavigationMenu.Root className="relative z-[1] flex w-full h-full justify-center">
|
<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 center">
|
<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.Item>
|
<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 asChild>
|
||||||
Projects
|
<Link
|
||||||
|
href="/projects"
|
||||||
|
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]"
|
||||||
|
>
|
||||||
|
Projects
|
||||||
|
</Link>
|
||||||
</NavigationMenu.Trigger>
|
</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">
|
<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-[0.75fr_1fr]">
|
<ul className="m-0 grid list-none gap-x-[10px] p-[22px] sm:w-[500px] sm:grid-cols-5">
|
||||||
<li className="grid row-span-3">
|
<li className="grid col-span-2 row-span-3">
|
||||||
<NavigationMenu.Link asChild>
|
<NavigationMenu.Link asChild>
|
||||||
<a
|
<Link
|
||||||
className="focus:shadow-violet7 from-purple9 to-indigo9 flex
|
className="focus:shadow-purple-500 from-purple-500 to-indigo-500 flex
|
||||||
h-full w-full select-none flex-col justify-end rounded-full bg-gradient-to-b p-[25px] no-underline outline-none focus:shadow-[0_0_0_2px]"
|
h-full w-full select-none flex-col justify-end rounded-lg bg-gradient-to-b p-[25px] no-underline outline-none focus:shadow-[0_0_0_2px]"
|
||||||
href="/"
|
href="/projects"
|
||||||
>
|
>
|
||||||
<svg
|
<BackpackIcon className="w-12 h-12 mb-2 text-white" />
|
||||||
aria-hidden
|
<div className="pb-4 text-[18px] font-bold leading-[1.2] text-white">
|
||||||
width="38"
|
Projects
|
||||||
height="38"
|
|
||||||
viewBox="0 0 25 25"
|
|
||||||
fill="white"
|
|
||||||
>
|
|
||||||
<path d="M12 25C7.58173 25 4 21.4183 4 17C4 12.5817 7.58173 9 12 9V25Z"></path>
|
|
||||||
<path d="M12 0H4V8H12V0Z"></path>
|
|
||||||
<path d="M17 8C19.2091 8 21 6.20914 21 4C21 1.79086 19.2091 0 17 0C14.7909 0 13 1.79086 13 4C13 6.20914 14.7909 8 17 8Z"></path>
|
|
||||||
</svg>
|
|
||||||
<div className="mt-4 mb-[7px] text-[18px] font-medium leading-[1.2] text-white">
|
|
||||||
Radix Primitives
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-mauve4 text-[14px] leading-[1.3]">
|
<p className="text-[14px] font-medium leading-[1.3]">
|
||||||
Unstyled, accessible components for React.
|
See the weird and wonderful things I've been
|
||||||
|
working on.
|
||||||
</p>
|
</p>
|
||||||
</a>
|
</Link>
|
||||||
</NavigationMenu.Link>
|
</NavigationMenu.Link>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
{projects.map((project) => (
|
||||||
|
<li
|
||||||
|
key={project.slug}
|
||||||
|
className="col-span-3 transition duration-150 rounded-md hover:bg-gray-900"
|
||||||
|
>
|
||||||
|
<NavigationMenu.Link asChild>
|
||||||
|
<Link
|
||||||
|
href={`/projects/${project.slug}`}
|
||||||
|
className={
|
||||||
|
"focus:shadow-[0_0_0_2px] focus:shadow-violet7 hover:bg-mauve3 block select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="mb-[5px] font-bold leading-[1.2]">
|
||||||
|
{project.title}
|
||||||
|
</div>
|
||||||
|
<p className="font-medium leading-[1.4]">
|
||||||
|
{project.subtitle}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</NavigationMenu.Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</NavigationMenu.Content>
|
</NavigationMenu.Content>
|
||||||
</NavigationMenu.Item>
|
</NavigationMenu.Item>
|
||||||
|
@ -79,8 +110,49 @@ export default function Navbar({
|
||||||
<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="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]">
|
||||||
Blog
|
Blog
|
||||||
</NavigationMenu.Trigger>
|
</NavigationMenu.Trigger>
|
||||||
<NavigationMenu.Content className="absolute top-0 left-0 w-full sm:w-auto">
|
<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-[600px] sm:grid-flow-col sm:grid-rows-3"></ul>
|
<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">
|
||||||
|
<NavigationMenu.Link asChild>
|
||||||
|
<Link
|
||||||
|
className="focus:shadow-green-500 from-green-500 to-cyan-500 flex
|
||||||
|
h-full w-full select-none flex-col justify-end rounded-lg bg-gradient-to-b p-[25px] no-underline outline-none focus:shadow-[0_0_0_2px]"
|
||||||
|
href="/blog"
|
||||||
|
>
|
||||||
|
<Pencil2Icon className="w-12 h-12 mb-2 text-white" />
|
||||||
|
<div className="pb-4 text-[18px] font-bold leading-[1.2] text-white">
|
||||||
|
Blog
|
||||||
|
</div>
|
||||||
|
<p className="text-[14px] font-medium leading-[1.3]">
|
||||||
|
Read my thoughts on the web, tech, and life.
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</NavigationMenu.Link>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{blogPosts.map((post) => (
|
||||||
|
<li
|
||||||
|
key={post.slug}
|
||||||
|
className="col-span-3 transition duration-150 rounded-md hover:bg-gray-900"
|
||||||
|
>
|
||||||
|
<NavigationMenu.Link asChild>
|
||||||
|
<Link
|
||||||
|
href={`/blog/${post.slug}`}
|
||||||
|
className={
|
||||||
|
"focus:shadow-[0_0_0_2px] focus:shadow-violet7 hover:bg-mauve3 block select-none rounded-[6px] p-3 text-[15px] leading-none no-underline outline-none transition-colors"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="mb-[5px] font-bold leading-[1.2]">
|
||||||
|
{post.title}
|
||||||
|
</div>
|
||||||
|
<p className="font-medium leading-[1.4]">
|
||||||
|
Categories: {post.categories.join(", ")}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</NavigationMenu.Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</NavigationMenu.Content>
|
</NavigationMenu.Content>
|
||||||
</NavigationMenu.Item>
|
</NavigationMenu.Item>
|
||||||
|
|
||||||
|
@ -98,7 +170,7 @@ export default function Navbar({
|
||||||
</NavigationMenu.Item>
|
</NavigationMenu.Item>
|
||||||
|
|
||||||
<NavigationMenu.Indicator className="data-[state=visible]:animate-fadeIn data-[state=hidden]:animate-fadeOut top-full z-[1] flex h-[10px] items-end justify-center overflow-hidden transition-[width,transform_250ms_ease]">
|
<NavigationMenu.Indicator className="data-[state=visible]:animate-fadeIn data-[state=hidden]:animate-fadeOut top-full z-[1] flex h-[10px] items-end justify-center overflow-hidden transition-[width,transform_250ms_ease]">
|
||||||
<div className="relative top-[70%] h-[10px] w-[10px] rotate-[45deg] rounded-tl-[2px] bg-white" />
|
<div className="relative top-[70%] h-[10px] w-[10px] rotate-[45deg] rounded-tl-[2px] bg-white dark:bg-gray-800" />
|
||||||
</NavigationMenu.Indicator>
|
</NavigationMenu.Indicator>
|
||||||
</NavigationMenu.List>
|
</NavigationMenu.List>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const heropatterns = require("tailwindcss-hero-patterns/src/patterns");
|
const heropatterns = require("tailwindcss-hero-patterns/src/patterns");
|
||||||
|
const plugin = require("tailwindcss/plugin");
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -19,8 +20,8 @@ module.exports = {
|
||||||
heroPatterns: {
|
heroPatterns: {
|
||||||
wiggle: heropatterns.wiggle,
|
wiggle: heropatterns.wiggle,
|
||||||
},
|
},
|
||||||
heroPatternsShades: ["100", "900"],
|
heroPatternsShades: ["100", "800"],
|
||||||
heroPatternsColors: ["indigo", "slate"],
|
heroPatternsColors: ["indigo", "zinc"],
|
||||||
extend: {
|
extend: {
|
||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
|
||||||
|
@ -79,16 +80,63 @@ module.exports = {
|
||||||
"20%, 60%": { transform: "rotate(25deg)" },
|
"20%, 60%": { transform: "rotate(25deg)" },
|
||||||
"40%, 80%": { transform: "rotate(0deg)" },
|
"40%, 80%": { transform: "rotate(0deg)" },
|
||||||
},
|
},
|
||||||
|
enterFromRight: {
|
||||||
|
from: { opacity: 0, transform: "translateX(200px)" },
|
||||||
|
to: { opacity: 1, transform: "translateX(0)" },
|
||||||
|
},
|
||||||
|
enterFromLeft: {
|
||||||
|
from: { opacity: 0, transform: "translateX(-200px)" },
|
||||||
|
to: { opacity: 1, transform: "translateX(0)" },
|
||||||
|
},
|
||||||
|
exitToRight: {
|
||||||
|
from: { opacity: 1, transform: "translateX(0)" },
|
||||||
|
to: { opacity: 0, transform: "translateX(200px)" },
|
||||||
|
},
|
||||||
|
exitToLeft: {
|
||||||
|
from: { opacity: 1, transform: "translateX(0)" },
|
||||||
|
to: { opacity: 0, transform: "translateX(-200px)" },
|
||||||
|
},
|
||||||
|
scaleIn: {
|
||||||
|
from: { opacity: 0, transform: "rotateX(-10deg) scale(0.9)" },
|
||||||
|
to: { opacity: 1, transform: "rotateX(0deg) scale(1)" },
|
||||||
|
},
|
||||||
|
scaleOut: {
|
||||||
|
from: { opacity: 1, transform: "rotateX(0deg) scale(1)" },
|
||||||
|
to: { opacity: 0, transform: "rotateX(-10deg) scale(0.95)" },
|
||||||
|
},
|
||||||
|
fadeIn: {
|
||||||
|
from: { opacity: 0 },
|
||||||
|
to: { opacity: 1 },
|
||||||
|
},
|
||||||
|
fadeOut: {
|
||||||
|
from: { opacity: 1 },
|
||||||
|
to: { opacity: 0 },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
"accordion-down": "accordion-down 0.2s ease-out",
|
"accordion-down": "accordion-down 0.2s ease-out",
|
||||||
"accordion-up": "accordion-up 0.2s ease-out",
|
"accordion-up": "accordion-up 0.2s ease-out",
|
||||||
"hand-wave": "hand-wave 2s ease-in-out infinite",
|
"hand-wave": "hand-wave 1.5s ease-in-out infinite",
|
||||||
|
scaleIn: "scaleIn 200ms ease",
|
||||||
|
scaleOut: "scaleOut 200ms ease",
|
||||||
|
fadeIn: "fadeIn 200ms ease",
|
||||||
|
fadeOut: "fadeOut 200ms ease",
|
||||||
|
enterFromLeft: "enterFromLeft 250ms ease",
|
||||||
|
enterFromRight: "enterFromRight 250ms ease",
|
||||||
|
exitToLeft: "exitToLeft 250ms ease",
|
||||||
|
exitToRight: "exitToRight 250ms ease",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require("tailwindcss-hero-patterns"),
|
require("tailwindcss-hero-patterns"),
|
||||||
require("tailwindcss-animate"),
|
require("tailwindcss-animate"),
|
||||||
|
plugin(({ matchUtilities }) => {
|
||||||
|
matchUtilities({
|
||||||
|
perspective: (value) => ({
|
||||||
|
perspective: value,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user