Skip to content
New: Customize your theme with an AI assistant. Read the guide

Collections

Skill level: Beginner · Files: src/content/<collection>/<language>/

A collection is a folder of similar entries: services, projects, job openings, blog posts. Each entry is one file and one page. The list page of the collection (for example /projects/) gets its own title and section blocks from the -index.md file in the same folder.

Add An Entry

  1. Copy an existing entry in the folder, for example src/content/projects/english/project-1.mdx.
  2. Rename the copy and change its customSlug, which sets the URL (/projects/my-new-project/). Collections whose entries have no customSlug use the file name.
  3. Change the frontmatter values and the Markdown body. Keep the keys.
  4. Add the same file in each other language folder with the translated text and the same customSlug.

To hide an entry, set draft: true. It still shows in npm run dev, but it is left out of the built site, the lists, and the sitemap. Services, projects, and open roles are ordered by weight (lowest first); blog posts by date (newest first).

A new entry with only a title won’t break the site, and it builds. Its card or page shows what you filled in, and images and other fields stay empty until you add them, so fill them in before you publish.

Collection Reference

The fields every page accepts (title, description, image, draft, customSlug, SEO fields) work on every entry. The table lists what each collection uses on top.

CollectionFolderURLFields
Servicesservices//services/<customSlug>/icon, image, weight, date, Markdown body, optional ctaSection
Projectsprojects//projects/<customSlug>/date, weight, categories, information, image, headerImageAlt, quote, Markdown body
Careerscareers//careers/<file>/department, location, type, salary, date, validThrough, weight, responsibilities, requirements, benefits, button
Blog postsblog//blog/<customSlug>/date, updated, author, categories, tags, image
Authorsauthor/(no page)title (the name), description, image
Teamteam//team/ onlyOne list in -index.md: title (the name), image, profession, description, email, phone, social
Testimonialstestimonial/(no page)One list in -index.md: content, image, customer (name, role, system, rating)

Services

The service pages power the services overview (/services/), the services section on the homepages, and the Services column in the footer. The Services mega menu in the header is separate: its links are in the menu file.

  • icon is a Lucide icon name in PascalCase, such as "BatteryCharging".
  • image is the photo on the card and at the top of the service page.
  • weight sets the order. The homepages show the first 4, the overview the first 6 (options.limit in each servicesSection), and the footer the first 6.
  • The body is Markdown: headings, lists, and a <Button> at the end. The [.h4] and [.h5] after a heading set its size (see Writing Content).
  • The page header badge comes from badgeSecondary in services/english/-index.md.

If you rename a service’s customSlug, update its links in the Services mega menu of every src/config/menu.*.json file.

Projects

Each project is a short case study:

title: "A family home that covers most of its own power"
customSlug: "family-home-rooftop"
description: "A 7.2 kWp roof array and a 10 kWh battery for a four-person household with an electric car."
date: 2026-06-12
weight: 1
categories:
- Residential # also the badge on the project page
information: # the facts list on the project page
- label: "System size"
value: "7.2 kWp"
- label: "Location"
value: "Riverside"
image: "/images/photos/project-home-unsplash-VX0ZEZSwqnY.jpg"
headerImageAlt: "Single-storey home with a full solar array on the roof"
quote: # optional customer quote after the text
enable: true
content: "We used to dread the winter bills..."
name: "Homeowner"
role: "Riverside · 7.2 kWp + 10 kWh battery"

In information, value: "date" shows the project’s date and value: "categories" its categories. The grid on /projects/ shows options.limit projects (set in projects/english/-index.md, false for all), ordered by weight.

Careers

One file per open role, for example src/content/careers/english/electrician.md:

  • department groups roles on /careers/ (set groupByDepartment: false in careers-list-section.md for one flat list); weight orders them.
  • type is full-time, part-time, or contract. The labels shown for each type are in labels.types of careers/english/-index.md.
  • location, type, and salary appear as chips under the title. salary is free text, such as "$34 to $42 per hour".
  • responsibilities, requirements, and benefits are lists, shown under the headings set in labels.
  • The Apply card comes from apply in careers/english/-index.md. Its button ships as mailto:[email protected]: point it at your email, form, or hiring system. A role can set its own button to override it.
  • date, validThrough, location, type, and salary feed the job posting data (JobPosting) search engines read. Google allows this data only for real, open positions, so replace or delete the sample roles before launch, and remove a role when it is filled.

When no roles are published, /careers/ shows emptyText from careers-list-section.md.

Blog

  • Posts are .mdx files with title, customSlug, metaDescription, image, date, author, categories, tags, and draft.
  • Author. author: "Clara Morel" is shown under the title. If a matching file exists in src/content/author/english/ (the name in lowercase, with dashes: clara-morel.md), its details are added to the post’s structured data.
  • Categories and tags create their own list pages, /blog/category/<name>/ and /blog/tag/<name>/. showCategories: true in blog/english/-index.md shows category buttons above the grid.
  • The post list. /blog/ shows the newest posts as large photo cards, then the rest in a 3-column grid. In blog/english/-index.md, options.featured is the number of photo cards on the first page (0 hides them), and options.relatedLimit the number of related posts under each article (0 hides them).
  • Posts per page: pagination in config.toml.
  • RSS (/rss.xml, and /fr/rss.xml), reading time, and the Copy page links are automatic.

Team

The team page shows every item of list in src/content/team/english/-index.md. Members have no page of their own. image is a portrait (the demo uses 450×500 images). A member can have social links, where label is the icon name: Linkedin, Instagram, Facebook, X, or Youtube. The demo members have none.

Testimonials

Reviews live in one file, src/content/testimonial/english/-index.md, and are shown by the testimonials section on the main and EV homepages, the about page, and the services overview. Each review has the quote (content), a photo of the installed system (image, shown in the slider layout), and the customer’s name, role, and system (for example "7.2 kWp + battery"). The rating (1 to 5, default 5) sets the stars on each card in the wall layout, as on the about page; the other layouts don’t show it. options.limit in testimonial-section.md sets how many show, and summary the overall rating line. A page can show its own reviews instead with a list in its testimonialSection block, as the renewable energy homepage does (see Section Layouts).

Do It With AI

Add a [service | project | job opening | blog post | team member | testimonial] to
src/content/[folder]/english/ for: [DETAILS]. Copy the frontmatter keys of an existing entry in
that folder, keep its comments, and fill in my values only. Use a customSlug (or file name) that
makes a good URL. Then create a version in each other language folder of src/content/[folder]/
with the same customSlug.
Type something to search...