/** * Blog-domain type definitions. The framework-free primitives many modules share * (`SiteConfig`, `LocaleConfig`, `TocEntry`, `PageMetadata`, `SitemapEntry`) live in * `../shared/types.js` and are re-exported here so every existing `./types.js` import in this * module (and the React components' `../blog/types.js` imports) keeps resolving unchanged. */ import type { LocaleConfig, SiteConfig } from "../shared/types.js"; export type { LocaleConfig, PageMetadata, SiteConfig, SitemapEntry, TocEntry } from "../shared/types.js"; /** * Front-matter for a blog post, normalised from the MDX file's YAML header. */ export interface PostMeta { /** * This language's URL slug: the file's front-matter `slug:` when it declares one, else the * post's directory name (`/`). Unique per language; a translation keeps its own slug. */ slug: string; /** * The post's directory name - the key that pairs its translations and names its hero/assets * folder - set ONLY when it differs from {@link PostMeta.slug} (a locale file declared its own * `slug:`). Read it as `meta.folder ?? meta.slug`; a post without a `slug:` override is * byte-identical to before the field existed. */ folder?: string | undefined; /** * Language code of this post, derived from its file name within the post folder: the default * locale for `` (or the `post` fallback), else the * `` file's stem. */ lang: string; /** Post title. Falls back to the slug when the front-matter omits it. */ title: string; /** Publish date as an ISO `YYYY-MM-DD` string (empty when unset). */ date: string; /** One-sentence summary, used for cards, meta description, and OG/Twitter. */ description: string; /** SEO keywords. */ keywords?: string[] | undefined; /** One or more category labels (usually one), used for the overview's filter buttons. */ categories?: string[] | undefined; /** Estimated whole-minute reading time, precomputed from the body at parse time. */ readingTime?: number | undefined; /** Author name; SEO helpers fall back to `SiteConfig.defaultAuthor` when unset. */ author?: string | undefined; /** * Author avatar image path served from the site root (front-matter key `author-image`), * e.g. `/assets/blog/authors/jane-doe.jpg`. Shown beside the author name in the post's * meta row and in the author bio at the end of the post. */ authorImage?: string | undefined; /** * Where the author's name links to (front-matter key `author-url`), e.g. `/about` or an * absolute profile URL. When set, the name in the meta row and in the closing bio renders as a * link through the page's `linkComponent`; when unset both stay plain text, exactly as before. * Per language, like every other field: a translated post links its own locale's page. */ authorUrl?: string | undefined; /** Hero / OG image path served from the site root, e.g. `/assets/blog//hero.en.jpg`. */ image?: string | undefined; /** Last-updated date as an ISO `YYYY-MM-DD` string. */ updated?: string | undefined; } /** * A parsed blog post: its normalised front-matter plus the raw MDX body. */ export interface Post { /** Normalised front-matter. */ meta: PostMeta; /** The MDX body (front-matter stripped), ready for ``. */ content: string; } /** * Configuration for a {@link import("./blog.js").Blog} instance. The site attributes from * {@link SiteConfig} are passed directly (flattened) alongside the content options; provide * at least `siteUrl` and `brandName` to enable the SEO methods (`postMetadata`, `postJsonLd`, * ...) and JSON-LD. */ export interface BlogConfig extends Partial { /** * Directory holding one `/` folder per post - each with a default-language body named * by its locale, `/` (e.g. `en.mdx`; the language-neutral * `/post` also works), plus optional `/` translations - * e.g. `./blog`. Relative paths are resolved against `process.cwd()`; absolute paths are used * as-is. */ contentDir: string; /** Post file extension, including the leading dot. Defaults to `.mdx`. */ extension?: string | undefined; /** BCP 47 locale used by `formatDate`. Defaults to `en-GB`. */ locale?: string | undefined; /** * Languages this blog is published in. Leave unset for a single-language blog (behaviour is * unchanged). When set, a post in a non-default language lives in the post's own folder as * `/` (e.g. `fr.mdx`) and is served under `//`, with * hreflang/`og:locale` linking it to its siblings. The `defaultLocale` (from {@link SiteConfig}) * is the post's `/` (e.g. `en.mdx`; or `post`) and is * served unprefixed; it defaults to the first entry's `code`. */ locales?: LocaleConfig[] | undefined; }