diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index 32f8c50d..00000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-24.13.1
diff --git a/app/(home)/icons/domainstack.png b/app/(home)/icons/domainstack.png
new file mode 100644
index 00000000..f911f6de
Binary files /dev/null and b/app/(home)/icons/domainstack.png differ
diff --git a/app/(home)/icons/snoozle.png b/app/(home)/icons/snoozle.png
new file mode 100644
index 00000000..0529dc19
Binary files /dev/null and b/app/(home)/icons/snoozle.png differ
diff --git a/app/(home)/icons/sofa.png b/app/(home)/icons/sofa.png
new file mode 100644
index 00000000..d800c071
Binary files /dev/null and b/app/(home)/icons/sofa.png differ
diff --git a/app/(home)/icons/versioneer.png b/app/(home)/icons/versioneer.png
new file mode 100644
index 00000000..c853a5b1
Binary files /dev/null and b/app/(home)/icons/versioneer.png differ
diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx
new file mode 100644
index 00000000..c368ac16
--- /dev/null
+++ b/app/(home)/page.tsx
@@ -0,0 +1,104 @@
+import { ArrowUpRight } from "lucide-react";
+import Image, { type StaticImageData } from "next/image";
+import Link from "next/link";
+
+import domainstackIcon from "./icons/domainstack.png";
+import snoozleIcon from "./icons/snoozle.png";
+import sofaIcon from "./icons/sofa.png";
+import versioneerIcon from "./icons/versioneer.png";
+
+type Project = {
+ name: string;
+ url: string;
+ tagline: string;
+ icon: StaticImageData;
+};
+
+const projects: readonly Project[] = [
+ {
+ name: "Domainstack",
+ url: "https://domainstack.io",
+ tagline: "Domain intelligence made easy",
+ icon: domainstackIcon,
+ },
+ {
+ name: "Sofa",
+ url: "https://sofa.watch",
+ tagline: "Self-hosted movie & TV show tracker",
+ icon: sofaIcon,
+ },
+ {
+ name: "Versioneer",
+ url: "https://versioneer.app",
+ tagline: "macOS app updater with privacy-friendly crowdsourcing",
+ icon: versioneerIcon,
+ },
+ {
+ name: "Snoozle",
+ url: "https://snoozle.ai",
+ tagline: "AI-powered bedtime stories for kids",
+ icon: snoozleIcon,
+ },
+] as const;
+
+const Page = () => (
+ <>
+
+ Hi there! I’m Jake.{" "}
+
+ 👋
+
+
+
+
+
+ I’m a developer based in the{" "}
+
+ Boston
+ {" "}
+ area working on some cool stuff:
+
+
+
+
+ >
+);
+
+export default Page;
diff --git a/app/birthday/opengraph-image.png b/app/birthday/opengraph-image.png
deleted file mode 100644
index da85b0f0..00000000
Binary files a/app/birthday/opengraph-image.png and /dev/null differ
diff --git a/app/birthday/page.tsx b/app/birthday/page.tsx
deleted file mode 100644
index e6414944..00000000
--- a/app/birthday/page.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { JsonLd } from "react-schemaorg";
-import type { VideoObject } from "schema-dts";
-
-import { PageTitle } from "@/components/layout/page-title";
-import { Video } from "@/components/video";
-import { createMetadata } from "@/lib/metadata";
-
-import thumbnail from "./thumbnail.png";
-
-export const metadata = createMetadata({
- title: "🎉 Cranky Birthday Boy on VHS Tape 📼",
- description: "The origin of my hatred for the Happy Birthday song.",
- canonical: "/birthday",
- openGraph: {
- videos: [
- {
- url: "https://ijyxfbpcm3itvdly.public.blob.vercel-storage.com/birthday-pavk1LBK4H6xF8ZWeR0oTcaabGuQ8T.webm",
- type: "video/webm",
- },
- ],
- },
-});
-
-const Page = () => (
- <>
-
- item={{
- "@context": "https://schema.org",
- "@type": "VideoObject",
- name: metadata.title as string,
- description: metadata.description as string,
- contentUrl:
- "https://ijyxfbpcm3itvdly.public.blob.vercel-storage.com/birthday-pavk1LBK4H6xF8ZWeR0oTcaabGuQ8T.webm",
- thumbnailUrl: `${process.env.NEXT_PUBLIC_BASE_URL}${thumbnail.src}`,
- embedUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/birthday`,
- uploadDate: "1996-02-06T00:00:00Z",
- duration: "PT6M10S",
- }}
- />
-
- 1996.mov
-
-
- >
-);
-
-export default Page;
diff --git a/app/birthday/thumbnail.png b/app/birthday/thumbnail.png
deleted file mode 100644
index da85b0f0..00000000
Binary files a/app/birthday/thumbnail.png and /dev/null differ
diff --git a/app/globals.css b/app/globals.css
index cabc8965..688965cd 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -2,6 +2,7 @@
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "react-lite-youtube-embed/dist/LiteYouTubeEmbed.css";
+@plugin "@tailwindcss/typography";
@custom-variant dark (&:where(.dark *));
@@ -201,159 +202,7 @@
cursor: pointer;
}
- .prose {
- @apply text-foreground/90 max-w-none text-sm leading-7;
-
- /* Headings */
- h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- @apply text-primary scroll-m-20 font-semibold tracking-tight;
- }
- h1 {
- @apply mt-8 mb-4 text-2xl leading-tight;
- }
- h2 {
- @apply mt-8 mb-4 border-b pb-2 text-xl leading-tight;
- }
- h3 {
- @apply mt-6 mb-3 text-lg leading-snug;
- }
- h4 {
- @apply mt-6 mb-2 text-base leading-snug;
- }
- h5 {
- @apply mt-4 mb-2 text-base leading-snug;
- }
- h6 {
- @apply mt-4 mb-2 text-sm leading-snug;
- }
-
- /* Text blocks */
- p {
- @apply text-foreground/90 my-4;
- }
- strong {
- @apply text-primary font-semibold;
- }
- em {
- @apply italic;
- }
-
- /* Separators */
- hr {
- @apply my-8 border-0 border-t;
- border-color: var(--border);
- }
-
- /* Links */
- a {
- @apply text-primary font-medium underline underline-offset-4 transition-colors;
- }
- a:hover {
- @apply opacity-80;
- }
-
- /* Lists */
- ul {
- @apply my-4 ml-6 list-disc;
- }
- ol {
- @apply my-4 ml-6 list-decimal;
- }
- li {
- @apply text-foreground/80;
- }
- li + li {
- @apply mt-1;
- }
- li > ul,
- li > ol {
- @apply my-2;
- }
-
- /* Blockquotes */
- blockquote {
- @apply my-6 border-l-4 pl-4 italic;
- border-color: var(--border);
- }
- blockquote p {
- @apply text-foreground/75;
- }
- blockquote *::before,
- blockquote *::after {
- content: none;
- }
-
- /* Inline code */
- :not(pre) > code {
- @apply bg-muted text-foreground rounded-sm px-1 py-0.5 text-[0.9em];
- }
- :not(pre) > code::before,
- :not(pre) > code::after {
- content: none;
- }
-
- /* Code blocks */
- pre {
- @apply bg-muted my-6 overflow-x-auto rounded-lg p-4 text-sm leading-6;
- }
- pre code {
- @apply bg-transparent p-0 text-inherit;
- }
- pre code::before,
- pre code::after {
- content: none;
- }
-
- /* Tables */
- table {
- @apply my-6 w-full border-collapse text-sm;
- }
- thead {
- @apply border-b;
- }
- tr {
- @apply border-b;
- }
- th {
- @apply text-primary px-3 py-2 text-left align-middle font-semibold;
- }
- td {
- @apply text-foreground/90 px-3 py-2 align-middle;
- }
-
- /* Images / media */
- img {
- @apply my-6 rounded-lg border;
- }
- video {
- @apply my-6 rounded-lg;
- }
-
- /* Misc */
- kbd {
- @apply bg-muted rounded border px-1.5 py-0.5 text-xs;
- }
- mark {
- @apply bg-muted rounded px-1;
- }
-
- /* First/last child spacing cleanup */
- > :first-child {
- @apply mt-0;
- }
- > :last-child {
- @apply mb-0;
- }
- }
-}
-
-/* View Transitions - uses tw-animate-css's `enter` and `exit` keyframes */
-@layer base {
+ /* View Transitions - uses tw-animate-css's `enter` and `exit` keyframes */
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
@@ -383,3 +232,8 @@
animation: 200ms ease-out forwards enter;
}
}
+
+/* Prose */
+.markdown {
+ @apply prose prose-neutral dark:prose-invert prose-sm prose-hr:border-foreground/20 prose-headings:font-semibold prose-headings:text-primary prose-headings:tracking-tight prose-p:text-foreground/90 prose-strong:text-primary prose-li:text-foreground/80 prose-a:text-primary prose-a:font-medium prose-a:underline prose-a:underline-offset-4 prose-blockquote:[&_p]:text-foreground/75 prose-blockquote:*:before:content-none prose-blockquote:*:after:content-none prose-code:bg-muted prose-code:text-foreground prose-code:px-1 prose-code:py-0.5 prose-code:rounded-sm prose-code:text-[0.9em] prose-code:before:content-none prose-code:after:content-none max-w-none [&_table]:!border-[color:var(--border)] [&_td]:!border-[color:var(--border)] [&_th]:!border-[color:var(--border)];
+}
diff --git a/app/hillary/opengraph-image.png b/app/hillary/opengraph-image.png
deleted file mode 100644
index 9fb1cf8b..00000000
Binary files a/app/hillary/opengraph-image.png and /dev/null differ
diff --git a/app/hillary/page.tsx b/app/hillary/page.tsx
deleted file mode 100644
index 9d123c71..00000000
--- a/app/hillary/page.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { JsonLd } from "react-schemaorg";
-import type { VideoObject } from "schema-dts";
-
-import { PageTitle } from "@/components/layout/page-title";
-import { Video } from "@/components/video";
-import { createMetadata } from "@/lib/metadata";
-
-import thumbnail from "./thumbnail.png";
-
-export const metadata = createMetadata({
- title: "My Brief Apperance in Hillary Clinton's DNC Video",
- description:
- "My brief apperance in one of Hillary Clinton's 2016 DNC convention videos on substance abuse.",
- canonical: "/hillary",
- openGraph: {
- videos: [
- {
- url: "https://ijyxfbpcm3itvdly.public.blob.vercel-storage.com/convention-ZTUBLwMcmOE8EJ4tNAhpCli4NAHKcG.webm",
- type: "video/webm",
- },
- ],
- },
-});
-
-const Page = () => (
- <>
-
- item={{
- "@context": "https://schema.org",
- "@type": "VideoObject",
- name: metadata.title as string,
- description: metadata.description as string,
- contentUrl:
- "https://ijyxfbpcm3itvdly.public.blob.vercel-storage.com/convention-ZTUBLwMcmOE8EJ4tNAhpCli4NAHKcG.webm",
- thumbnailUrl: `${process.env.NEXT_PUBLIC_BASE_URL}${thumbnail.src}`,
- embedUrl: `${process.env.NEXT_PUBLIC_BASE_URL}/hillary`,
- uploadDate: "2016-07-25T00:00:00Z",
- duration: "PT1M51S",
- }}
- />
-
- HRC.mov
-
-
-
-
- Video is property of{" "}
-
- Hillary for America
-
- , the{" "}
-
- Democratic National Committee
-
- , and{" "}
-
- CNN / WarnerMedia
-
- . © 2016.
-
- >
-);
-
-export default Page;
diff --git a/app/hillary/thumbnail.png b/app/hillary/thumbnail.png
deleted file mode 100644
index 9fb1cf8b..00000000
Binary files a/app/hillary/thumbnail.png and /dev/null differ
diff --git a/app/layout.tsx b/app/layout.tsx
index b8281dba..cc51452d 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -63,11 +63,13 @@ const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => (
-
-
- {children}
-
-
+
+
+
+ {children}
+
+
+
diff --git a/app/notes/[slug]/page.tsx b/app/notes/[slug]/page.tsx
index e5b5b507..d4d1c3f7 100644
--- a/app/notes/[slug]/page.tsx
+++ b/app/notes/[slug]/page.tsx
@@ -179,7 +179,9 @@ const Page = async ({ params }: { params: Promise<{ slug: string }> }) => {
/>
-
+
+
+
- Hi there! I’m Jake.{" "} - - 👋 - -
- -- I’m a frontend web developer based in the{" "} - - Boston - {" "} - area. -
- -- I’m always available to connect over{" "} - - email - {" "} - - -
-
-- 2B0C 9CF2 51E6 9A39 -- - - . -