feat: add hero background images to case study detail pages
Some checks failed
Build & Push / build-and-push (push) Has been cancelled

Each project page now has its image behind the hero text with a
dark gradient overlay for readability. Tags use a glass-morphism
style on the image background.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 16:46:21 -04:00
parent 1f6bb7d066
commit 40e9a257f7

View File

@@ -1,3 +1,4 @@
import Image from 'next/image';
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { setRequestLocale } from 'next-intl/server'; import { setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing'; import { routing } from '@/i18n/routing';
@@ -17,6 +18,7 @@ interface Project {
outcome: string; outcome: string;
techStack: string[]; techStack: string[];
tags: string[]; tags: string[];
image: string;
} }
// ─── Data (will come from Payload CMS) ──────────────────────────────────────── // ─── Data (will come from Payload CMS) ────────────────────────────────────────
@@ -35,6 +37,7 @@ const PROJECTS: Record<string, Project> = {
"The platform processed over 200 submissions in its first season, reducing judge workload by 40% through AI-assisted pre-screening. The client praised the system's reliability and the elegance of its interface.", "The platform processed over 200 submissions in its first season, reducing judge workload by 40% through AI-assisted pre-screening. The client praised the system's reliability and the elegance of its interface.",
techStack: ['Next.js', 'PostgreSQL', 'OpenAI API', 'Docker', 'Private Cloud'], techStack: ['Next.js', 'PostgreSQL', 'OpenAI API', 'Docker', 'Private Cloud'],
tags: ['AI Integration', 'Platform'], tags: ['AI Integration', 'Platform'],
image: '/images/monaco_high_res.jpg',
}, },
'port-nimara': { 'port-nimara': {
title: 'Port Nimara', title: 'Port Nimara',
@@ -48,6 +51,7 @@ const PROJECTS: Record<string, Project> = {
'The new platform increased online berth inquiries by 3x and provided the port authority with real-time content management capabilities they previously lacked.', 'The new platform increased online berth inquiries by 3x and provided the port authority with real-time content management capabilities they previously lacked.',
techStack: ['Nuxt.js', 'Directus CMS', 'Node.js', 'Docker'], techStack: ['Nuxt.js', 'Directus CMS', 'Node.js', 'Docker'],
tags: ['Website', 'Infrastructure'], tags: ['Website', 'Infrastructure'],
image: '/images/anguilla.png',
}, },
'port-amador': { 'port-amador': {
title: 'Port Amador', title: 'Port Amador',
@@ -61,6 +65,7 @@ const PROJECTS: Record<string, Project> = {
"The redesigned platform elevated Port Amador's digital presence to match their premium positioning, with a 60% improvement in page load times and significantly increased organic traffic.", "The redesigned platform elevated Port Amador's digital presence to match their premium positioning, with a 60% improvement in page load times and significantly increased organic traffic.",
techStack: ['Next.js', 'Tailwind CSS', 'Framer Motion', 'Vercel'], techStack: ['Next.js', 'Tailwind CSS', 'Framer Motion', 'Vercel'],
tags: ['Website', 'Infrastructure'], tags: ['Website', 'Infrastructure'],
image: '/images/panama.png',
}, },
}; };
@@ -123,38 +128,53 @@ export default async function CaseStudyPage({ params }: Props) {
<main> <main>
{/* ── Hero ── */} {/* ── Hero ── */}
<section className="bg-surface-low py-24"> <section className="relative min-h-[420px] md:min-h-[480px] flex items-end overflow-hidden">
<div className="container mx-auto px-6"> {/* Background image */}
<div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-6"> <Image
src={project.image}
alt=""
fill
className="object-cover"
sizes="100vw"
priority
/>
{/* Dark overlay for text readability */}
<div className="absolute inset-0 bg-gradient-to-t from-[rgba(25,28,29,0.85)] via-[rgba(25,28,29,0.55)] to-[rgba(25,28,29,0.3)]" />
<div className="relative z-10 container mx-auto px-6 pb-16 pt-32">
<div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-5">
{/* Tags */} {/* Tags */}
<ScrollReveal variant="fadeIn"> <ScrollReveal variant="fadeIn">
<div className="flex flex-wrap items-center justify-center gap-2"> <div className="flex flex-wrap items-center justify-center gap-2">
{project.tags.map((tag) => ( {project.tags.map((tag) => (
<Chip key={tag} size="md"> <span
key={tag}
className="inline-flex items-center bg-white/15 backdrop-blur-sm text-white/90 text-[0.75rem] font-semibold px-3 py-1 rounded-full leading-none tracking-wide"
>
{tag} {tag}
</Chip> </span>
))} ))}
</div> </div>
</ScrollReveal> </ScrollReveal>
{/* Title */} {/* Title */}
<ScrollReveal variant="fadeUp" delay={0.08}> <ScrollReveal variant="fadeUp" delay={0.08}>
<h1 className="font-serif font-semibold text-on-surface text-4xl md:text-5xl lg:text-[3.25rem] leading-[1.1] tracking-[-0.02em]"> <h1 className="font-serif font-semibold text-white text-4xl md:text-5xl lg:text-[3.25rem] leading-[1.1] tracking-[-0.02em]">
{project.title} {project.title}
</h1> </h1>
</ScrollReveal> </ScrollReveal>
{/* Subtitle */} {/* Subtitle */}
<ScrollReveal variant="fadeUp" delay={0.16}> <ScrollReveal variant="fadeUp" delay={0.16}>
<p className="label-md text-primary tracking-widest"> <p className="label-md text-white/70 tracking-widest">
{project.subtitle} {project.subtitle}
</p> </p>
</ScrollReveal> </ScrollReveal>
{/* Description */} {/* Description */}
<ScrollReveal variant="fadeUp" delay={0.22}> <ScrollReveal variant="fadeUp" delay={0.22}>
<p className="text-outline text-lg leading-relaxed max-w-2xl"> <p className="text-white/80 text-lg leading-relaxed max-w-2xl">
{project.description} {project.description}
</p> </p>
</ScrollReveal> </ScrollReveal>