Skip to content

Commit 398ad36

Browse files
committed
feat: generate blog posts content via markdown
1 parent b77e45a commit 398ad36

10 files changed

Lines changed: 526 additions & 77 deletions

File tree

app/pages/blog/[...path].vue

Lines changed: 0 additions & 62 deletions
This file was deleted.

app/pages/blog/[slug].vue

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<script setup lang="ts">
2+
const route = useRoute()
3+
const { data: post } = await useAsyncData(route.path, () => {
4+
return queryCollection('blog').path(route.path).first()
5+
})
6+
7+
definePageMeta({
8+
name: `blog-post`,
9+
// alias: ['/:path(.*)*'],
10+
})
11+
12+
useSeoMeta({
13+
title: () => post.value?.title || 'Blog', // TODO: How does i18n deal with dynamic values? $t('blog.post.title'),
14+
description: () => (post.value?.description ? `Blog Article ${post.value?.description}` : ''),
15+
})
16+
</script>
17+
18+
<template>
19+
<main class="container py-8 sm:py-12 w-full">
20+
<!-- Header -->
21+
<header class="mb-8 pb-8 border-b border-border">
22+
<div class="">I AM A WEAK HEADER</div>
23+
</header>
24+
25+
<article v-if="post">
26+
<ContentRenderer v-if="post" :value="post" />
27+
</article>
28+
29+
<article v-else>
30+
<h1>Post Not Found</h1>
31+
<p>We couldn't find a post at /blog/{{ route.path }}</p>
32+
</article>
33+
</main>
34+
</template>
35+
36+
<!-- TODO: styles -->
37+
<style>
38+
h1 {
39+
@apply text-4xl font-bold text-gray-900 dark:text-white mb-2;
40+
}
41+
</style>

app/pages/blog/index.vue

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
<script setup lang="ts">
2-
const route = useRoute('blog')
3-
const router = useRouter()
4-
5-
// 1. Define your list of posts (This would eventually come from useAsyncData)
6-
const posts = [
7-
{ slug: 'hello-world', title: 'Hello World', excerpt: 'My first post' },
8-
{ slug: 'server-components', title: 'Server Components', excerpt: 'Zero JS' },
9-
]
2+
const { data: posts } = await useAsyncData('blog-posts', () =>
3+
queryCollection('blog').where('draft', '<>', true).order('date', 'DESC').all(),
4+
)
105
116
definePageMeta({
127
name: 'blog',

content.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineContentConfig, defineCollection } from '@nuxt/content'
2+
import { BlogPostSchema } from './shared/schemas/blog'
3+
4+
export default defineContentConfig({
5+
collections: {
6+
blog: defineCollection({
7+
type: 'page',
8+
source: 'blog/**/*.md',
9+
schema: BlogPostSchema,
10+
}),
11+
},
12+
})

content/blog/first-post.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: 'Hello World'
3+
date: '2026-01-28'
4+
slug: 'first-post'
5+
description: 'My first post on the blog'
6+
excerpt: 'My first post'
7+
draft: false
8+
---
9+
10+
# My First Page
11+
12+
Here is some content.

content/blog/server-components.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: 'Server Components'
3+
date: '2026-01-28'
4+
slug: 'server-components'
5+
description: 'My first post on the blog'
6+
excerpt: 'Zero JS'
7+
draft: false
8+
---
9+
10+
# Server components
11+
12+
Here is some server component razzle dazzle.

nuxt.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export default defineNuxtConfig({
3232
'@vueuse/nuxt',
3333
'@nuxtjs/i18n',
3434
'@nuxtjs/color-mode',
35+
'@nuxt/content',
3536
],
3637

3738
colorMode: {

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build:lunaria": "node --experimental-transform-types ./lunaria/lunaria.ts",
1414
"dev": "nuxt dev",
1515
"dev:docs": "pnpm run --filter npmx-docs dev --port=3001",
16+
"dev:blog": "pnpm run --filter npmx-blog dev --port=3002",
1617
"lint": "vite lint && vite fmt --check",
1718
"lint:fix": "vite lint --fix && vite fmt",
1819
"generate": "nuxt generate",
@@ -28,11 +29,13 @@
2829
"test:unit": "vite test --project unit"
2930
},
3031
"dependencies": {
32+
"@atproto/lex": "^0.0.13",
3133
"@deno/doc": "jsr:^0.189.1",
3234
"@iconify-json/simple-icons": "^1.2.67",
3335
"@iconify-json/vscode-icons": "^1.2.40",
3436
"@lunariajs/core": "https://pkg.pr.new/lunariajs/lunaria/@lunariajs/core@f07e1a3",
3537
"@nuxt/a11y": "1.0.0-alpha.1",
38+
"@nuxt/content": "3.11.0",
3639
"@nuxt/fonts": "^0.13.0",
3740
"@nuxt/scripts": "^0.13.2",
3841
"@nuxtjs/color-mode": "^4.0.0",
@@ -69,6 +72,7 @@
6972
"@types/validate-npm-package-name": "4.0.2",
7073
"@unocss/nuxt": "66.6.0",
7174
"@unocss/preset-wind4": "66.6.0",
75+
"@valibot/to-json-schema": "^1.5.0",
7276
"@vite-pwa/assets-generator": "1.0.2",
7377
"@vite-pwa/nuxt": "1.1.0",
7478
"@vitest/browser-playwright": "^4.0.18",

0 commit comments

Comments
 (0)