Editing the content — Titen Next.js
All the words and images of the site live in src/content/. You edit plain TypeScript files (quotes around text, commas
between items), and the site updates while npm run dev is running. No CMS is needed. If you would rather manage
content in Sanity, Payload, Strapi or Directus, see Using a headless CMS.
src/content/ site.ts name, description, domain, menu, header button, contact details, footer, the project form pages/home.ts the copy of the home page pages/about.ts …and of every other page (About also holds the team and the awards) collections/*.ts project categories, projects, services, posts, testimonials routes.ts the URL of every page types.ts the fields each kind of item hasNot sure which file holds a piece of text? The page maps label every section of every page with its file.
Your details first
Section titled “Your details first”src/content/site.ts holds what appears on every page:
| Export | Shown where |
|---|---|
site.name |
Logo label, browser title suffix, share cards |
site.title |
Browser title of the home page |
site.description |
Search results and share cards, for pages without their own description |
site.url |
Set this to your domain before publishing. Canonical links, share links, sitemap.xml and robots.txt are built from it. |
navigation |
The menu in the header (and the phone menu) |
headerAction |
The button on the right of the header (“Contact us”) |
search |
The “Search projects” label and the search field’s placeholder |
contact |
E-mail, phone and address: used in the footer and on the Contact page |
socials |
The social links at the bottom of the footer |
footer |
“Let’s Talk!” with its text and button, the tagline, the “Mail us” / “Call us” labels, the Work and Studio columns, the newsletter, the copyright line ({year} becomes the current year) |
projectForm |
“Let’s Work Together” at the end of Projects, the category pages and every service page: title, text, image, fields, button and messages. The Contact page uses the same fields. |
The demo’s e-mail (contact@example.com), phone number and address are placeholders: replace all three. The footer’s
Work column lists the project categories by itself.
Page copy
Section titled “Page copy”There is one file per page in src/content/pages/. Each exports an object with the sections of that page and, for
pages with a fixed URL, a meta entry:
export const aboutPage = { meta: { title: "About", // browser tab: "About | Titen" description: "Titen is an architecture…", // search results and share cards (80–160 characters) }, hero: { … }, values: [ … ],};Change the text between the quotes, keeping the field names: the sections read them by name. Apostrophes are safe inside double quotes, and the demo uses the typographic ’. A double quote inside a double-quoted string needs a backslash before it.
| File | Page |
|---|---|
home.ts |
Home. It has no meta: its title and description are site.title and site.description. |
about.ts |
About, including the six team members (team.members) and the five awards (awards.items) |
projects.ts, services.ts, contact.ts, testimonials.ts |
The pages of the same name |
blog.ts |
The Blog page (blogPage) and the words shared by every post (postPage: “Related”, “Similar Posts”) |
category.ts |
The title and description of the category pages; {category} becomes the category’s name |
project.ts, service.ts |
The words shared by every project and service page (labels, “Other Projects”, the brochure button) |
not-found.ts |
The 404 page |
Collections
Section titled “Collections”src/content/collections/ holds the lists the site builds pages from:
| File | What it feeds |
|---|---|
categories.ts |
One page per category (/residential, /hospitality, /commercial), the buttons on Projects and the footer’s Work column |
projects.ts |
The Projects page, one page per project, the search in the header, Home (the first seven), its category’s page, “Other Projects” at the end of a project (up to three more of the same category), and the small photos on Services and Contact (the first six project images) |
services.ts |
The Services page, one page per service, and the expanding list on Home and Testimonials (the first four) |
posts.ts |
The Blog, one page per post, Home (the first three) and “Similar Posts” at the end of a post (up to three of the same category) |
testimonials.ts |
The Testimonials page and the slideshow in the Home hero (the first five) |
The order of the items in the file is the order on the site.
Adding a project
Section titled “Adding a project”Copy an existing entry, paste it below, and change the values:
{ slug: "harbour-library", // the URL: /projects/harbour-library title: "Harbour Library", location: "Oslo, Norway", year: "2026", category: "commercial", // the slug of a category in categories.ts image: "/images/project-harbour-library.jpg", // cards and the top of the project page (about 1920 × 1280) summary: "A public library on the water…", // cards, the top of the page, the search description intro: { text: "…", // next to the details (location, category, year) image: "/images/project-harbour-library-intro.jpg", // portrait, about 800 × 1100 gallery: ["/images/…-gallery-1.jpg", "/images/…-gallery-2.jpg", "/images/…-gallery-3.jpg"], }, story: { image: "/images/…-story.jpg", text: "…", wide: "/images/…-wide.jpg" }, details: { texts: ["…", "…"], gallery: ["/images/…", "/images/…", "/images/…"] }, closing: [{ text: "…", image: "/images/…-closing.jpg" }], // one part, or two}A project page has four parts (five when closing has two entries). A text can hold several paragraphs: separate them
with an empty line (\n\n).
Adding a service
Section titled “Adding a service”{ slug: "acoustic-design", // the URL: /services/acoustic-design number: "09", // shown on the Services page title: "Acoustic Design", overview: "Spaces that sound as good as…", // the service lists and the search description image: "/images/service-acoustic-design.jpg", // about 1400 × 1050 points: ["…", "…", "…", "…", "…"], // "Key Point": five short lines about: "…", // "About the service" on its page included: [ … ], // "What's included": rich text, see below}Adding a category, post or testimonial
Section titled “Adding a category, post or testimonial”| Add | Fields |
|---|---|
| Category | slug (the URL, /<slug>) and title. Then set category on its projects. Pick a slug that isn’t already a page (about, blog, contact, …). |
| Post | slug, title, excerpt (the card text), image (about 1920 × 1280), category (any words; posts with the same one are listed under each other as “Similar Posts”), author, date ("2024-03-12"), body (rich text) |
| Testimonial | slug, quote, name, photo (round, about 96 px), and rating (out of 5, e.g. 4.8; leave it out to show the star alone) |
A post’s search description is its title followed by its excerpt (cut at 160 characters).
Team and awards
Section titled “Team and awards”The team and the awards appear only on About, so they live in src/content/pages/about.ts:
team.members:name,role,bio,photo(portrait, about 800 × 1000) andlinkedin.awards.items:title,award(the name in orange),descriptionandyear.
Removing an item
Section titled “Removing an item”Delete the entry. Its page, its card and its sitemap entry disappear on the next build. A project names its category by
slug: if you delete a category, give its projects another one.
What each field means
Section titled “What each field means”src/content/types.ts is the reference: it lists every field, which are optional (?), and a comment for the ones
that are not obvious. Your editor shows the same information while you type.
Rich text: posts and “What’s included”
Section titled “Rich text: posts and “What’s included””A post body, or a service’s included, is a list of blocks:
body: [ { type: "heading", text: "Why natural light matters" }, { type: "paragraph", text: "A plain paragraph." }, { type: "paragraph", highlight: "Bold start:", text: " and the rest of the paragraph." }, { type: "list", items: [ // bullets; ordered: true for numbers [{ type: "paragraph", text: "First item" }], [{ type: "paragraph", highlight: "Second:", text: " with a bold start" }], ] },]Each list item is itself a list of blocks, so a numbered item can hold paragraphs and a nested list. Text is plain: the
bold parts are highlight, not **stars**.
Videos
Section titled “Videos”Two videos play on the site. Each has a src (a web address or a file) and a poster (the picture shown before it
plays):
| Video | Where it plays | Field |
|---|---|---|
| Hero video | Home, behind the title, under a dark cover | hero.video in src/content/pages/home.ts |
| Studio video | About, between the approach slideshow and the team | video in src/content/pages/about.ts |
The demo plays stock clips, which are not part of the download: the About clip plays from the web, and the hero’s
public/videos/home-hero.mp4 in the download is a short placeholder. To use your own, put an MP4 in
public/videos/ and set src: "/videos/hero.mp4". Keep a wide format (16:9), export at about 1280–1920 px wide, and
keep each file small (a few MB): they play muted and in a loop. Replace the matching poster in public/images/ too. For
visitors who prefer reduced motion, only the poster shows.
The demo’s hero clip is a free stock video from Magnific, whose license asks for a credit: “Designed by Magnific”,
shown small at the bottom right of the hero (hero.video.credit in home.ts). Remove it when you use your own video.
The brochure
Section titled “The brochure”“Download our brochure” (Home) and “Download Brochure” (every service page) download public/brochure.pdf. The file in
the download is a placeholder page: replace it with your own PDF under the same name, or change the href in
src/content/pages/home.ts and service.ts.
Images
Section titled “Images”- Put the file in
public/images/. - Refer to it in the content as
/images/<file>(the path starts atpublic).
Sizes and formats are handled for you: pages use next/image, which serves a scaled, modern format per device. Use
photos at least as wide as they appear: wide photos 1920 px, project photos 1000–1920 px, service photos 1400 px,
portraits 800 px. Keep the demo’s aspect ratios, because the layout crops to fit.
Two things sit outside the content because browsers and social networks ask for them by name:
| File | What it is |
|---|---|
src/app/icon.svg, src/app/apple-icon.png |
The icon in the browser tab and on a phone’s home screen |
public/opengraph-image.png |
The picture shown when someone shares a link (2400 × 1260; 1200 × 630 or larger) |
Its description for screen readers is shareImage.alt in src/lib/meta.ts. Every page uses this image when shared,
except the project, service and post pages, which share their own image.
Text that is not in content/
Section titled “Text that is not in content/”Almost every word is content, including the forms’ messages (projectForm and footer.newsletter in site.ts). The
few interface words that never change per site live in the code:
- “Menu” (the phone menu button’s label for screen readers) and “Clear” (the search field) in
src/design-system/; - “Testimonials” (the name of the Home slideshow for screen readers) in
src/components/sections/HomeHeroSection.tsx.
Search for the word and you will find it.
After editing
Section titled “After editing”npm run buildA successful build means every page, link and image still resolves. See Going live for the rest of the checklist.