announcementwriting · 3 min read

Hello World

A sample post showing every field the blog collection supports, from frontmatter through to MDC components.
A cracked desert plain strewn with dinosaur skeletons and distant ruins under a stormy sunset, with small green shoots pushing up through the broken earth.

This post exists so the blog_en collection has something real to query. Delete it once your own writing lands — or keep it around as a reference for the frontmatter shape.

Frontmatter

Every field above is validated by the schema in content.config.ts. Adding a field that is not in the schema is fine — it just will not be typed. Removing a required one fails the build, which is the point.

draft: true keeps a post out of production listings. Filter on it when you query:

const { data: posts } = await useAsyncData('blog', () =>
  queryCollection('blog_en')
    .where('draft', '=', false)
    .order('createdAt', 'DESC')
    .all(),
)

Writing

Markdown works as you would expect — bold, italic, inline code, and links.

Blockquotes render through the prose components the UI layer ships.

MDC is supported, so any auto-imported Vue component can be used directly in the body:

This is a callout, written in Markdown.

Images

The featured image is a Cloudflare Images delivery URL. Upload the file, then put the URL the command prints into image.src:

pnpm images:upload ./cover.png --kind cover --slug hello-world

The listing and the post header both read it from there. The post header shows it behind a small blurred placeholder, and so does any image in the body that points at Images; the listing cards load a thumbnail instead. Both are variants of the same URL, which is why flexible variants have to be enabled once on the account.

A same-origin path under public/ works too, just without the placeholder or the thumbnail. docs/blog.md in the repository covers the whole pipeline.

That is the whole loop: write a file, get a typed, queryable document.

Last updated