Skip to main content

Portfolio (Case Studies)

Routes

RoutePurpose
/workFull project grid with filter chips
/work/[category]Pre-filtered grid for one category
/work/[category]/[slug]Cinematic case study detail page

Key rule: filtered pages must pre-filter

/work/[category]/page.tsx must filter projects to the active category AND pass defaultCategory to ProjectGrid. Rendering the grid without pre-filtering produces a blank or all-projects page.

Components

ProjectGrid

Client Component. Accepts projects + optional defaultCategory. Renders FilterChips + stagger-animated Framer Motion grid.

ProjectCard

Server Component. Links to /work/[category]/[slug]. Featured cards get a cyan glow border (featured === true).

Case study page components

ComponentTypeWhat it renders
ProjectHeroClient60vh hero — iframe for video, gradient for image
ProjectInfoServerTwo-column: title/description/deliverables + meta
ProjectGalleryClientLightbox image grid (only if gallery has items)
ProjectProcessServerNumbered step list from processSteps
ProjectResultsClientStat card row from results + outcome prose
ProjectNavClientPrevious / Next project cards

Static generation

export async function generateStaticParams() {
const projects = await getAllProjects({ status: 'published' });
return projects.map((p) => ({ category: p.category, slug: p.slug }));
}

Add export const dynamicParams = false once project data is stable — unknown slugs 404 at the routing layer.

Admin: creating a case study from a lead

On any lead detail page → QuickActions card → "Create Case Study" maps the lead data into a draft project and redirects to /admin/projects/[id] to finish filling it out.