Skip to content
Sign inJoin waitlist

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 has

Not sure which file holds a piece of text? The page maps label every section of every page with its file.

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.

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

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.

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).

{
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
}
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).

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) and linkedin.
  • awards.items: title, award (the name in orange), description and year.

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.

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**.

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.

“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.

  1. Put the file in public/images/.
  2. Refer to it in the content as /images/<file> (the path starts at public).

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.

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.

Terminal window
npm run build

A successful build means every page, link and image still resolves. See Going live for the rest of the checklist.