Project Detail Pages
Relevant source files
The following files were used as context for generating this wiki page:
Project Detail Pages serve as the primary dynamic routing mechanism for displaying individual portfolio items. These pages are built using Next.js App Router and leverage Sanity as a headless CMS to provide structured content including project overviews, client details, technical stacks (tags), and chronological durations.
The system utilizes static site generation (SSG) with on-demand revalidation and support for Draft Mode, allowing content creators to preview changes in real-time before publishing.
Sources: app/(personal)/projects/[slug]/page.tsx:1-12, README.md:14-25
Data Architecture and Schema
Projects are defined as a standard document type in Sanity. The schema is highly structured, containing basic metadata, media assets, and rich text fields for detailed descriptions.
Project Document Schema
The project document type includes fields for identification (title, slug), visual representation (coverImage), and project-specific metadata (client, site, tags).
| Field | Type | Description |
|---|---|---|
title | string | The name of the project. Required. |
slug | slug | URL identifier derived from the title. |
overview | array (block) | A brief subheader/SEO description (max 155 chars). |
coverImage | image | The main visual asset for the project. |
duration | duration | Object containing start and end ISO dates. |
client | string | Name of the organization the project was built for. |
site | url | External link to the live project. |
tags | array (string) | Categories or technologies used. |
description | array | Rich text (Portable Text) including images and timelines. |
Sources: sanity/schemas/documents/project.ts:7-115, sanity.types.ts:51-110
Entity Relationship Diagram
This diagram illustrates how the project document interacts with various object types like duration and timeline.
The project schema allows for nested complex objects, such as a timeline block within the description field.
Sources: sanity/schemas/documents/project.ts:98-101, sanity/schemas/objects/milestone.ts:44-48
Technical Implementation
The project detail route is located at app/(personal)/projects/[slug]/page.tsx. It implements several Next.js specific functions for SEO and performance.
Data Fetching and Dynamic Routing
The page uses sanityFetch to retrieve content based on the URL slug. It supports static generation via generateStaticParams.
*generateMetadata**: Dynamically generates the page title and OpenGraph images using the project's title and coverImage.
generateStaticParams: Queries all project slugs to pre-render pages at build time.ProjectSlugRoute: The main component that extracts data and handles 404 states if a project is not found (unless in Draft Mode).
Sources: app/(personal)/projects/[slug]/page.tsx:18-63, sanity/lib/queries.ts:31-45
Presentation and Components
The project page is composed of several specialized components:
- Header: Displays the title and overview.
- ImageBox: Renders the
coverImagewith Sanity-native hotspot/crop support. - CustomPortableText: Renders the complex
descriptionfield, supporting custom blocks like images and timelines.
Sources: app/(personal)/projects/[slug]/page.tsx:82-146, sanity/schemas/documents/project.ts:88-114
Visual Editing and Resolvers
To support the side-by-side editing experience in Sanity Studio's Presentation tool, the project pages are linked to specific routes via resolvers.
The resolve.ts file defines how the Studio maps a project document to its frontend URL. It uses the project document's title and slug to generate a valid location for the previewer.
Sources: sanity/plugins/resolve.ts:11-48, sanity.config.ts:48-51
Conclusion
Project Detail Pages are a core part of the personal website's dynamic content delivery. By combining structured Sanity schemas with Next.js dynamic routes and Portable Text, the system ensures that project portfolios are technically optimized for SEO, performant via static generation, and easily maintainable through a native authoring environment.