Hello World
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:
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