Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/types/root-params.d.ts";
import "./.next/dev/types/routes.d.ts";
import "./.next/dev/types/root-params.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
2 changes: 2 additions & 0 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Navbar from "@/components/layout/Navbar";
import Hero from "@/components/sections/hero/Hero";
import About from "@/components/sections/about/About";
import Projects from "@/components/sections/projects/Projects";
import Highlights from "@/components/sections/highlights/Highlights";
import Skills from "@/components/sections/skills/Skills";
import Education from "@/components/sections/education/Education";
import Contact from "@/components/sections/contact/Contact";
Expand All @@ -30,6 +31,7 @@ export default function Home() {
<Navbar />
<Hero />
<Projects />
<Highlights />
<About />
<Skills />
<Education />
Expand Down
2 changes: 1 addition & 1 deletion src/components/sections/about/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function About() {
<section id="about" className="border-b border-white/[0.07] px-5 py-20 sm:px-8 sm:py-24 lg:px-10 lg:py-32">
<div className="mx-auto max-w-7xl">
<SectionHeading
eyebrow="02 / About"
eyebrow="03 / About"
title="Engineering across the AI and product stack."
description="I work from system behavior and trust boundaries through APIs, data, interfaces, tests, and deployment."
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/sections/contact/Contact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function Contact() {
<div className="pointer-events-none absolute -bottom-32 -left-32 h-96 w-96 rounded-full bg-accent/[0.06] blur-[120px]" aria-hidden="true" />
<div className="relative mx-auto max-w-7xl">
<SectionHeading
eyebrow="05 / Contact"
eyebrow="06 / Contact"
title="Looking for an AI or full-stack engineer?"
description="I am open to AI Engineer and Full-stack Engineer opportunities, as well as thoughtful open-source and technical collaborations."
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/sections/education/Education.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default function Education() {
return (
<section id="education" className="border-b border-white/[0.07] px-5 py-20 sm:px-8 sm:py-24 lg:px-10">
<div className="mx-auto max-w-7xl">
<SectionHeading eyebrow="04 / Education" title="Learning grounded in building." />
<SectionHeading eyebrow="05 / Education" title="Learning grounded in building." />
<ul className="mt-12 border-b border-white/[0.09] md:mt-16">
{educationItems.map((item) => (
<li key={item} className="grid gap-3 border-t border-white/[0.09] py-5 text-stone-400 sm:grid-cols-[2.5rem_1fr] sm:items-start sm:py-6">
Expand Down
56 changes: 56 additions & 0 deletions src/components/sections/highlights/HighlightCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Highlight, HighlightIcon } from "@/content/highlights";

function HighlightIcon({ icon }: { icon: HighlightIcon }) {
const paths: Record<HighlightIcon, string> = {
"open-source": "M8 9l-3 3 3 3m8-6l3 3-3 3m-5 2l2-10",
hackathons: "M8 21h8M12 17v4m-5-8V4h10v5a5 5 0 01-10 0zm0-5H4v2a3 3 0 003 3m10-5h3v2a3 3 0 01-3 3",
certifications: "M12 3l2.2 4.45 4.92.72-3.56 3.47.84 4.9L12 15.2l-4.4 2.34.84-4.9-3.56-3.47 4.92-.72L12 3z",
projects: "M4 7h16M4 12h16M4 17h16M7 4h10a1 1 0 011 1v14a1 1 0 01-1 1H7a1 1 0 01-1-1V5a1 1 0 011-1z",
"ai-engineering": "M12 3v3m0 12v3M3 12h3m12 0h3M5.64 5.64l2.12 2.12m8.48 8.48l2.12 2.12m0-12.72l-2.12 2.12M7.76 16.24l-2.12 2.12M16 12a4 4 0 11-8 0 4 4 0 018 0z",
"full-stack": "M4 5h16v10H4V5zm4 14h8m-4-4v4",
community: "M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2m8-10a4 4 0 100-8 4 4 0 000 8zm6-3a3 3 0 110-6m4 15v-2a4 4 0 00-3-3.87",
building: "M5 20V9l7-5 7 5v11M3 20h18M9 20v-5h6v5M9 9h.01M15 9h.01",
};

return (
<svg
className="h-5 w-5"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path d={paths[icon]} />
</svg>
);
}

export default function HighlightCard({ highlight, index }: { highlight: Highlight; index: number }) {
return (
<article className="group flex min-h-64 flex-col justify-between border-b border-r border-white/[0.09] p-6 transition-colors hover:border-accent/40 sm:p-7">
<div className="flex items-start justify-between gap-4">
<span className="inline-flex h-10 w-10 items-center justify-center rounded-sm border border-white/[0.12] text-stone-500 transition-colors group-hover:border-accent/50 group-hover:text-accent">
<HighlightIcon icon={highlight.icon} />
</span>
<span className="text-xs tabular-nums tracking-[0.16em] text-stone-700">
{String(index + 1).padStart(2, "0")}
</span>
</div>

<div className="mt-10">
<h3 className="text-xl font-semibold tracking-[-0.025em] text-stone-100 transition-colors group-hover:text-accent">
{highlight.title}
</h3>
<p className="mt-3 text-sm leading-6 text-stone-400">
<span className="mr-2 text-2xl font-semibold tracking-[-0.04em] text-stone-200">
{highlight.value}
</span>
{highlight.description}
</p>
</div>
</article>
);
}
23 changes: 23 additions & 0 deletions src/components/sections/highlights/Highlights.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import SectionHeading from "@/components/ui/SectionHeading";
import { highlights } from "@/content/highlights";
import HighlightCard from "./HighlightCard";

export default function Highlights() {
return (
<section id="highlights" className="border-b border-white/[0.07] bg-surface px-5 py-20 sm:px-8 sm:py-24 lg:px-10 lg:py-32">
<div className="mx-auto max-w-7xl">
<SectionHeading
eyebrow="02 / Highlights"
title="The signal behind the work."
description="A compact view of the practice, projects, and systems I keep building in public."
/>

<div className="mt-14 grid border-l border-t border-white/[0.09] sm:grid-cols-2 lg:mt-20 lg:grid-cols-4" aria-label="Portfolio highlights">
{highlights.map((highlight, index) => (
<HighlightCard key={highlight.title} highlight={highlight} index={index} />
))}
</div>
</div>
</section>
);
}
2 changes: 1 addition & 1 deletion src/components/sections/skills/Skills.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default function Skills() {
<section id="skills" className="border-b border-white/[0.07] bg-surface px-5 py-20 sm:px-8 sm:py-24 lg:px-10 lg:py-32">
<div className="mx-auto max-w-7xl">
<SectionHeading
eyebrow="03 / Core stack"
eyebrow="04 / Core stack"
title="The tools behind the work."
description="A focused stack reflected in the projects above—not a catalogue of generic capabilities."
/>
Expand Down
67 changes: 67 additions & 0 deletions src/content/highlights.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
export type HighlightIcon =
| "open-source"
| "hackathons"
| "certifications"
| "projects"
| "ai-engineering"
| "full-stack"
| "community"
| "building";

export interface Highlight {
title: string;
value: string;
description: string;
icon: HighlightIcon;
}

export const highlights: Highlight[] = [
{
title: "Open Source",
value: "10+",
description: "contributions",
icon: "open-source",
},
{
title: "Hackathons",
value: "4",
description: "participations",
icon: "hackathons",
},
{
title: "Certifications",
value: "3",
description: "completed",
icon: "certifications",
},
{
title: "Projects",
value: "Builds",
description: "Production & open-source builds",
icon: "projects",
},
{
title: "AI Engineering",
value: "AI",
description: "Agents, LLM tooling & automation",
icon: "ai-engineering",
},
{
title: "Full-Stack",
value: "Stack",
description: "Next.js, TypeScript, Python & APIs",
icon: "full-stack",
},
{
title: "Community",
value: "Open",
description: "Open-source engineering and knowledge sharing",
icon: "community",
},
{
title: "Building",
value: "Now",
description: "GraphKeeper + Omniveer",
icon: "building",
},
];
9 changes: 9 additions & 0 deletions tests/homepage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ test("homepage positioning and responsive layout", async ({ page }, testInfo) =>
await expect(menuButton).toHaveAttribute("aria-expanded", "false");
}

const highlightsHeading = page.getByRole("heading", {
name: "The signal behind the work.",
});
await highlightsHeading.scrollIntoViewIfNeeded();
await expect(highlightsHeading).toBeVisible();
await expect(page.locator("#highlights article")).toHaveCount(8);
await expect(page.locator("#highlights")).toContainText("Open Source");
await expect(page.locator("#highlights")).toContainText("GraphKeeper + Omniveer");

const projectsHeading = page.getByRole("heading", {
name: "AI systems, built end to end.",
});
Expand Down
Loading