Add Nuxt frontend with blog index, article and category pages

The browser never talks to Strapi: pages call Nitro endpoints under
server/api/, which are the only place Strapi queries are built. That keeps the
Strapi URL internal to the Docker network and avoids CORS entirely.

Article bodies are rendered from Markdown to HTML in the endpoint, so the
content is server-rendered and crawlable, marked stays out of the client
bundle, and the meta description is derived from the opening of the body.

Pages carry canonical URLs, Open Graph tags and BlogPosting structured data,
and handle empty, missing and failed states.
This commit is contained in:
2026-08-25 11:42:17 +02:00
parent ec5976135f
commit a808f1010f
28 changed files with 10387 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
/** Shape of the Strapi payloads, narrowed to what the site actually renders. */
export interface StrapiImage {
url: string
alternativeText: string | null
width: number | null
height: number | null
}
export interface Category {
name: string
slug: string
}
/** An article as returned by the listing endpoints. */
export interface ArticleSummary {
title: string
slug: string
publishedAt: string
cover: StrapiImage | null
category: Category | null
}
/** A single article, with the body already rendered to HTML server-side. */
export interface Article extends ArticleSummary {
html: string
/** Plain-text opening of the body, used as the meta description. */
summary: string
}
export interface Paginated<T> {
items: T[]
page: number
pageCount: number
total: number
}
+10
View File
@@ -0,0 +1,10 @@
/** Human-readable date for display; returns an empty string when unset. */
export function formatDate(value: string | null | undefined): string {
if (!value) return ''
return new Intl.DateTimeFormat('it-IT', { dateStyle: 'long' }).format(new Date(value))
}
/** Machine-readable date for the `datetime` attribute and structured data. */
export function isoDate(value: string | null | undefined): string {
return value ? new Date(value).toISOString() : ''
}