Projects, Photo Series & Archive
Files: src/content/projects/<language>/ (one file per project, plus -index.md), src/content/pages/<language>/archive.mdx · Skill level: Beginner
Your work lives in one collection: src/content/projects/. Each file is one project page at /projects/<file name>/. A project can be a case study, a split case with the facts beside the images, or a photo series. The same entries fill the projects list at /projects/, the archive at /archive/, the projects sections on the homepages, and the next-project link at the end of each project page.
The demo ships 12 projects: 4 case studies, 2 split cases, and 6 photo series. Replace them with your own work before launch.
Pick A Template
The options.layout value at the end of the frontmatter picks the page template. Every template reads the same fields.
options: layout: "default" # default | gallery | split| Template | What the page shows | Demo example |
|---|---|---|
default | A case study: page header with the facts, the cover across the page, the text, the figures, the image blocks, the client quote | ceramic-forms.md |
split | On large screens, a sticky column with the title, description, and facts beside one column of images. Then the text, figures, and quote | gift-bag.md |
gallery | A photo series: page header with the place, year, and number of photos, then every image in a masonry grid that opens a lightbox, then the text | north-atlantic.md |
All three end with a link to the next project and the call to action. Case studies and split cases also show the client logos.
Add A Project
-
Copy the demo entry that matches your template, for example
src/content/projects/english/ceramic-forms.md. -
Rename the copy. The file name becomes the URL (
/projects/my-project/) and the project’s id, which other files use to point to it. -
Put the images in their own folder, for example
src/assets/images/projects/my-project/. In content files, write the path from/images/:/images/projects/my-project/cover.jpg. -
Change the frontmatter values and the Markdown body. Keep the keys.
-
Add the same file name in
src/content/projects/french/andsrc/content/projects/arabic/, with the translated text and the same image paths.
To hide a project, set draft: true. It still shows in npm run dev, but it is left out of the built site and every list.
Project Fields
title, description, image, draft, and the SEO fields work as on every page (Pages). ceramic-forms.md shows every field with a comment.
| Field | What it does |
|---|---|
image | The cover, 4:3. Also the project card |
imageAlt | Describes the cover for screen readers |
client | The client’s name, in the facts strip. A case study’s title is usually the client’s name |
year | Text, so a range such as "2023–2024" works |
role, services | Your role, and a list of services, in the facts strip |
duration | How long the project took, in the facts strip |
location | For a photo series: where the photos were taken |
information | Extra rows for the facts strip: - label: "Printing" / value: "One-colour labels" |
liveUrl | Adds a “Visit site” link. Empty hides it |
categories | The filter chips on /projects/ and /archive/. Use the same spelling in every entry of a language |
tags | Keywords for search engines. They are not shown on the page |
result | One line about the outcome. The subtitle in the index and stack list layouts |
metrics | 2 or 3 figures in a band: - value: "40" / label: "Glazes on one layout". Write the final text; the figure counts up |
quote | A client quote: text, emphasis (a part of text, copied exactly, set in a heavier weight), name, role, and image (a square portrait, or "") |
images | The image, video, and text blocks of the page, in order (below) |
next | The id of the next project. Empty: the next one of the same kind by weight, back to the first after the last |
featured | true or false. The project card in the Services menu uses the first project with featured: true when its cta.project is empty (see Navigation). The demo names ceramic-forms there, so featured changes nothing until you empty it |
weight | The order in every list, lowest first. Entries without a weight go last |
options.layout | The template: default, gallery, or split |
The Markdown body (## Overview, ## Approach, ## Result in the demo) is the case study text. A photo series can have a short body too.
related takes a list of project ids. The project pages in this version don’t show it.
Image Blocks
images is the list of blocks on the page, in order. Each block has a type and a size.
images: - type: "image" src: "/images/projects/my-project/gallery-1.jpg" alt: "Describe what is visible, for screen readers." caption: "Optional line under the image and in the lightbox." size: "full" - type: "video" src: "/videos/my-project.mp4" # a file in public/ or a full URL alt: "What the video shows." poster: "/images/projects/my-project/poster.jpg" size: "half" - type: "text" title: "One grid, forty names" body: "A short paragraph in **Markdown**." size: "half"type | Needs | What it shows |
|---|---|---|
image | src, alt | A framed image that opens the lightbox. image is the default when type is left out |
video | src, alt | A muted, looping video that plays while it is on screen, with the browser’s controls. poster is the still shown first |
text | body | A short heading (title) and a paragraph |
size | Width |
|---|---|
full | Across the page, 3:2 (the default) |
half | Two in a row, 4:3 |
third | Three in a row, 4:5 |
Phones show every block at full width. In the split template the images stack in one column, each in its own shape. In the gallery template every image is part of the masonry grid. Videos don’t start on their own for visitors who turn on reduce motion in their device settings.
npm run astro-check reports an image or video block without src or alt, and a text block without body.
The Projects Page
/projects/ takes its page header, layout, and options from src/content/projects/<language>/-index.md:
projectsSection: options: layout: "grid" # grid | index | wall | stack category: "" # one category, or empty for all items: [] # project ids in order; overrides `category` limit: 0 # at most this many (0 = all) filters: true # `grid` and `index`: category chips above the listWith filters: true, an “All” chip and one chip per category appear above the cards. The address keeps the chosen chip, such as /projects/#branding, so you can link to a filtered list. The page also shows the logos section (logosSection) and the call to action (ctaSection). For each layout, see Section Layouts.
The Archive
/archive/ lists every project as ruled rows, newest first: year, title, result, client, and services. Moving the mouse over a row shows its cover beside the pointer. Its file is src/content/pages/<language>/archive.mdx:
projectsSection: options: layout: "index" order: "year" # year (newest first) | weight filters: trueA photo series without a client reads “Personal series” in the client column.
Projects On Other Pages
Any page can show projects with a projectsSection: block, using the same options. The homepages use it with items to pick projects by id, and the studio homepage with the index layout. The hero stack and masthead layouts show a deck of projects from the hero’s cards list, and a gallery section can show the images of one photo series with options.project. See Homepages.
Change The Next-Project Link
The link at the end of each project page is the next-project section, src/content/sections/<language>/next-project-section.md. Its layout is banner (one large link) or cards (the previous and next projects). label and seriesLabel are the small labels above the title, for a case study and a photo series. A project file can change them for its own page with a nextProjectSection: block.
Do It With AI
Add a [case study | split case | photo series] to src/content/projects/english/ called [NAME].Copy the frontmatter of [ceramic-forms.md | gift-bag.md | north-atlantic.md], keep its comments,and set options.layout to [default | split | gallery]. Use these facts: [CLIENT, YEAR, ROLE,SERVICES, CATEGORIES]. My images are in src/assets/images/projects/[NAME]/; write alt text foreach and use paths starting with /images/. Write the body from these notes: [NOTES]. Then createthe french and arabic versions with the same file name, and run npm run astro-check.