import { FileNode } from '../types'; import { ContentRef } from './types'; /** One post in a content manifest. `source` is Markdown text (inline or a #241 reference). */ export interface BlogPost { /** URL-safe id; becomes the `.md` filesystem key and the permalink target. */ slug: string; /** Display title (the window/desktop label and mirror `

`/``). */ title: string; /** ISO date string (RSS `pubDate`, sortable). */ date?: string; /** * Markdown source (#137), inline or referenced (#241). A `string` is the * inline body (the common case); a `{ url }` / `{ asset }` {@link ContentRef} * moves a long post out of the manifest. Inline sources render everywhere; * referenced sources become a `contentRef` file node and must be pre-resolved * (pass `bodyHtml`) for the crawlable mirror, which needs the text at build time. */ source: ContentRef; /** Optional icon id for the file node. */ icon?: string; /** Optional single containing folder key (posts group under it on the desktop). */ folder?: string; /** Optional short summary for RSS / meta description. */ excerpt?: string; /** Optional tags (from frontmatter `tags:`); passed through to authors' own UIs. */ tags?: string[]; } export type ContentManifest = BlogPost[]; /** Parsed Markdown frontmatter: the leading `--- … ---` block plus the body after it. */ export interface Frontmatter { /** Key → scalar or list value. Keys are lower-cased; scalars are unquoted. */ data: Record<string, string | string[]>; /** The Markdown body with the frontmatter block removed. */ body: string; } /** * Parse a Markdown string's leading frontmatter (#254). Supports `key: value` * scalars, inline lists (`tags: [a, b]`) and block lists (`- a` on following * lines); keys are lower-cased and scalar values unquoted. No frontmatter → * `{ data: {}, body: raw }`. Deliberately tiny (no YAML dependency) — it covers * what a blog post's header needs, not the whole YAML spec. */ export declare function parseFrontmatter(raw: string): Frontmatter; /** * Build a {@link BlogPost} from raw Markdown with frontmatter (#254) — the * natural authoring on-ramp: `import.meta.glob('./posts/*.md', { as: 'raw' })` * then `postFromMarkdown(src, { slug })`. Reads `title/date/excerpt/folder/icon/ * tags` (and `description` as an excerpt alias) from the frontmatter, falling * back to `defaults`. `source` keeps the original text (frontmatter included) so * MarkdownViewer can render the title/date header; RSS/sitemap/mirror read the * parsed fields. A `slug` is required (frontmatter `slug:` or `defaults.slug`). */ export declare function postFromMarkdown(raw: string, defaults?: Partial<Omit<BlogPost, 'source'>>): BlogPost; /** Site-level metadata for feeds and mirror pages. */ export interface SiteMeta { title: string; description?: string; /** Absolute site origin+path the desktop is served from, e.g. `https://me.dev/`. */ siteUrl: string; /** Optional language passed through to the permalink (`&lang=`). */ language?: string; } /** The filesystem key path a post opens at (folder-aware). */ export declare function postPath(post: BlogPost): string[]; /** * Build a `customFileSystem` fragment from a manifest (#137). Posts become * `<slug>.md` file nodes bound to MarkdownViewer; posts sharing a `folder` * nest under that folder. Merge the result into `customFileSystem`. */ export declare function buildContentFs(manifest: ContentManifest): Record<string, FileNode>; /** Absolute permalink that opens a post's window on a fresh load (#136 deep link). */ export declare function postPermalink(post: BlogPost, site: SiteMeta): string; /** * Build an RSS 2.0 feed string from a manifest (#137). Each item links to the * post's desktop permalink so subscribers land on the open window. */ export declare function buildRssFeed(manifest: ContentManifest, site: SiteMeta): string; /** * Build a `sitemap.xml` (sitemaps.org 0.9) from a manifest (#254) — completes * the SEO trio (RSS feed + per-post mirror + sitemap). Emits the site root plus * one `<url>` per post pointing at its desktop permalink, with `<lastmod>` when * the post has a `date` (use an ISO / `YYYY-MM-DD` date for a valid sitemap). */ export declare function buildSitemap(manifest: ContentManifest, site: SiteMeta): string; /** * Build a crawlable static mirror page for a post (#137, SEO pattern). Pass * `bodyHtml` — e.g. `renderToStaticMarkup(renderMarkdown(post.source))` at build * time — for rich content; without it the raw Markdown is escaped into a `<pre>` * fallback so crawlers still index the text. The page links back to the desktop * permalink, so search engines index content while humans get the desktop. * * A referenced source (#241, `{ url }`/`{ asset }`) has no text available * synchronously, so pass `bodyHtml` (e.g. resolve the ref at build time) for * those posts; without it the mirror body is empty. */ export declare function buildPostMirrorHtml(post: BlogPost, site: SiteMeta, bodyHtml?: string): string;