Files
matheoguilbert.fr/app/[locale]/works/[slug]/page.tsx
T
mguilbert 26256f0379 redesign(project-page): editorial redesign of /works/[slug]
- ProjectHero: full-viewport dark hero with blurred cover image overlay,
  animated entrance (back link → date → title → description), scroll indicator
- ProjectMeta: reveal-animated metadata strip with top/bottom dividers,
  refined label/value typography using brand color tokens
- ProjectTechnologies: outline pill tags with per-tag staggered reveal,
  hover border/color transition
- ProjectsColumns: cleaner 2-col prose grid with wider gap
- ProjectPreviewGrid: rounded-xl with subtle border, responsive 1→2 col
- ProjectVisitButton: pill-shaped dark CTA replacing bordered rectangle
- OtherProjects: image-first card layout with scroll reveal, hover scale +
  brightness on covers, sliding arrow, refined "Voir aussi" header
- page.tsx: passes cover prop to ProjectHero, 900px max-width content
  column, semantic MDX prose styles via article selector chains

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 08:48:28 +02:00

83 lines
2.8 KiB
TypeScript

import { notFound } from "next/navigation";
import { MDXRemote } from "next-mdx-remote/rsc";
import { getAllProjects, getProjectBySlug, getProjectSlugs } from "@/lib/projects/get-projects";
import { mdxComponents } from "@/components/mdx/mdxComponents";
import { ProjectHero } from "@/components/sections/ProjectHero";
import { ProjectMeta } from "@/components/sections/ProjectMeta";
import { ProjectTechnologies } from "@/components/sections/ProjectTechnologies";
import { OtherProjects } from "@/components/sections/OtherProjects";
type props = {
params: Promise<{
locale: string;
slug: string;
}>;
};
export function generateStaticParams() {
return getProjectSlugs().flatMap((slug: any) => [
{ locale: "fr", slug },
{ locale: "en", slug },
]);
}
export default async function ProjectPage({ params }: props) {
const { locale, slug } = await params;
const project = getProjectBySlug(slug);
if (!project) {
notFound();
}
const otherProjects = getAllProjects()
.filter((item: any) => item.slug !== slug && item.ready)
.slice(0, 2)
.map((item: any) => ({
slug: item.slug,
title: item.title,
description: item.description,
cover: item.cover,
}));
return (
<main className="bg-brand-beige">
<ProjectHero
locale={locale}
title={project.title}
description={project.description}
dateLabel={project.dateLabel}
cover={project.cover}
/>
<div className="mx-auto max-w-[900px] px-8 md:px-14 lg:px-6">
<ProjectMeta
dateLabel={project.dateLabel}
category={project.category}
roles={project.roles}
client={project.client}
/>
<ProjectTechnologies technologies={project.technologies} />
<section className="pb-16">
<article
className="
flex flex-col gap-16
[&_h2]:font-serif [&_h2]:text-[clamp(52px,6vw,80px)] [&_h2]:text-brand-brown [&_h2]:leading-none [&_h2]:mb-8 [&_h2]:mt-4
[&_p]:font-sans [&_p]:text-sm [&_p]:text-brand-brown/70 [&_p]:leading-[1.8]
"
>
<MDXRemote
source={project.content}
components={mdxComponents}
options={{ blockJS: false, blockDangerousJS: true }}
/>
</article>
</section>
<OtherProjects locale={locale} projects={otherProjects} />
</div>
</main>
);
}