Files
portfolio/app/projects/[slug]/page.tsx
T
2026-05-28 17:46:49 -07:00

131 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import { IconArrowNarrowLeft, IconExternalLink } from "@tabler/icons-react";
import Hero from "@/components/content/Hero";
import SectionLabel from "@/components/layout/SectionLabel";
import { colors, projects } from "@/constants";
export function generateStaticParams() {
return projects.map((project) => ({ slug: project.slug }));
}
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await params;
const project = projects.find((p) => p.slug === slug);
if (!project) return { title: "Project — Angel Mankel" };
return {
title: `${project.title} — Angel Mankel`,
description: project.description,
};
}
export default async function ProjectPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const project = projects.find((p) => p.slug === slug);
if (!project) notFound();
return (
<div className="space-y-14">
<Link
href="/projects"
className="inline-flex items-center gap-1 text-sm text-neutral-400 transition-colors hover:text-neutral-200"
>
<IconArrowNarrowLeft size={18} />
All projects
</Link>
<Hero label={project.title} subtitle={project.description}>
<div className="space-y-5">
<p className="text-md text-neutral-400">
{project.year} {project.stack.join(" · ")}
</p>
<a
href={project.liveUrl}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-2 rounded-lg border border-neutral-700 px-4 py-2 text-[15px] font-medium transition-colors hover:border-neutral-500"
style={{ color: colors.accent }}
>
Open live app
<IconExternalLink size={18} />
</a>
</div>
</Hero>
{/* Screenshots */}
{project.screenshots.length > 0 && (
<section className="space-y-4">
{project.screenshots.map((shot) => (
<div
key={shot.src}
className="overflow-hidden rounded-xl border border-neutral-800"
>
<Image
src={shot.src}
alt={shot.alt}
width={1200}
height={750}
className="h-auto w-full"
/>
</div>
))}
</section>
)}
{/* Overview */}
<section className="space-y-4">
<SectionLabel label="Overview" />
<div className="space-y-4 text-[17px] leading-[1.65] text-neutral-200">
{project.overview.map((paragraph) => (
<p key={paragraph}>{paragraph}</p>
))}
</div>
</section>
{/* What I learned */}
<section className="space-y-4">
<SectionLabel label="What I learned" />
<ul className="space-y-2 text-[15px] leading-[1.65] text-neutral-200">
{project.learned.map((item) => (
<li
key={item}
className="before:mr-2 before:text-neutral-600 before:content-['']"
>
{item}
</li>
))}
</ul>
</section>
{/* What I'd do differently */}
<section className="space-y-4">
<SectionLabel label="What I'd do differently" />
<ul className="space-y-2 text-[15px] leading-[1.65] text-neutral-200">
{project.improvements.map((item) => (
<li
key={item}
className="before:mr-2 before:text-neutral-600 before:content-['']"
>
{item}
</li>
))}
</ul>
</section>
</div>
);
}