Content Management¶
The website consumes content from a Strapi v5 headless CMS via a
server-side API client (src/lib/strapi.ts). All data fetching happens
at build time or request time with Incremental Static Regeneration
(60-second revalidation).
Strapi API Client¶
The client lives at src/lib/strapi.ts and provides typed functions
for each content type. Every request appends a public filter
(filters[publishTarget][$contains]=public) to ensure only published,
public-facing content is served.
Configuration¶
Variable |
Description |
|---|---|
|
Strapi base URL (default: |
|
ISR interval in seconds (hardcoded: 60) |
|
Applied to all queries automatically |
Available Functions¶
Pages:
fetchNavPages(locale)— Pages withshowInNav=true, sorted bysortOrderfetchPublicPages(locale)— All public pagesfetchPublicPage(slug, locale)— Single page by slug
Articles:
fetchPublicArticles(page, pageSize, locale, categorySlug?, tagSlug?)— Paginated article listing with optional filtersfetchPublicArticle(slug, locale)— Single article by slugfetchFeaturedArticles(locale, limit?)— Featured articles
Categories & Tags:
fetchCategories(locale?)— All categories sorted bysortOrderfetchTags()— All tags sorted by name
Media Collections:
fetchPublicMediaCollections(page, pageSize, locale)fetchPublicMediaCollection(slug, locale)
Helpers:
strapiMediaUrl(media)— Resolves absolute or relative media URLs
Content Types¶
All types are defined in src/lib/types.ts.
Article¶
Field |
Type |
Description |
|---|---|---|
|
string |
Article title |
|
string |
URL slug (unique per locale) |
|
string? |
Short description for listings |
|
string |
Full markdown body |
|
StrapiMedia? |
Featured image |
|
Author? |
Author relation |
|
Category? |
Single category relation |
|
Tag[] |
Many-to-many tag relations |
|
string[] |
Visibility ( |
|
boolean |
Show in featured sections |
|
string |
Content locale ( |
|
string? |
ISO date of publication |
Page¶
Field |
Type |
Description |
|---|---|---|
|
string |
Page title |
|
string |
URL slug (e.g., |
|
string? |
SEO meta description |
|
Section[] |
Dynamic zone (Hero, FeatureGrid, etc.) |
|
string[] |
Visibility |
|
number |
Navigation ordering |
|
boolean |
Show in navbar |
|
string |
Content locale |
CMS-Driven Pages¶
Pages fetched from Strapi use a dynamic zone pattern. Each page has a
sections array where each entry has a __component string identifying
which React component to render. The SectionRenderer component
dispatches accordingly:
// src/components/sections/SectionRenderer.tsx
const componentMap = {
"page-sections.hero": HeroSection,
"page-sections.feature-grid": FeatureGridSection,
"page-sections.rich-text": RichTextSection,
"page-sections.call-to-action": CallToActionSection,
"page-sections.image-gallery": ImageGallerySection,
};
If the CMS returns no home page, the site falls back to
StaticHomePage — a Figma-designed homepage with hero, features,
partner logos, and CTA sections.