Skip to content

Commit 66401ec

Browse files
committed
use metadata to autogenerate blog index
1 parent 5001e1d commit 66401ec

5 files changed

Lines changed: 85 additions & 6 deletions

File tree

.vitepress/theme/BlogPosts.vue

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import { data as posts } from './posts.data'
4+
5+
const props = defineProps<{
6+
folder: string
7+
}>()
8+
9+
const filteredPosts = computed(() => {
10+
return posts.filter((post) => post.url.startsWith(props.folder))
11+
})
12+
</script>
13+
14+
<template>
15+
<ul class="blog-posts">
16+
<li v-for="post in filteredPosts" :key="post.url">
17+
<div class="post-header">
18+
<a :href="post.url">{{ post.title }}</a>
19+
</div>
20+
<p class="post-description">{{ post.description }}</p>
21+
<div class="timestamp">{{ post.date }}</div>
22+
</li>
23+
</ul>
24+
</template>
25+
26+
<style scoped>
27+
.blog-posts {
28+
list-style: none;
29+
padding: 0;
30+
}
31+
32+
.blog-posts .post-header a {
33+
text-decoration: none !important;
34+
}
35+
36+
.blog-posts li {
37+
margin: 1.5em 0;
38+
}
39+
40+
.blog-posts .timestamp {
41+
margin-right: 0.5em;
42+
color: var(--vp-c-text-2);
43+
font-size: 0.8em;
44+
}
45+
46+
.post-description {
47+
margin: 0.25em 0 0 0;
48+
color: var(--vp-c-text-1);
49+
font-size: 0.9em;
50+
}
51+
</style>

.vitepress/theme/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import BlogSponsor from './BlogSponsor.vue'
55
import GitHubStars from './GitHubStars.vue'
66
import CodeTabs from './CodeTabs.vue'
77
import JetBrainsPluginButton from './JetBrainsPluginButton.vue'
8+
import BlogPosts from './BlogPosts.vue'
89
import './style.css'
910

1011
export default {
@@ -18,5 +19,6 @@ export default {
1819
enhanceApp({ app }) {
1920
app.component('CodeTabs', CodeTabs)
2021
app.component('JetBrainsPluginButton', JetBrainsPluginButton)
22+
app.component('BlogPosts', BlogPosts)
2123
},
2224
} satisfies Theme

.vitepress/theme/posts.data.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { createContentLoader } from 'vitepress'
2+
3+
export interface Post {
4+
title: string
5+
url: string
6+
date: string
7+
description: string
8+
}
9+
10+
declare const data: Post[]
11+
export { data }
12+
13+
export default createContentLoader(['blog/*.md', 'ru/blog/*.md'], {
14+
transform(raw): Post[] {
15+
return raw
16+
.filter((page) => page.url !== '/blog/' && page.url !== '/ru/blog/')
17+
.map((page) => ({
18+
title: page.frontmatter.title,
19+
url: page.url,
20+
date: formatDate(page.frontmatter.date),
21+
description: page.frontmatter.description,
22+
}))
23+
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
24+
},
25+
})
26+
27+
function formatDate(date: string | Date): string {
28+
const d = new Date(date)
29+
return d.toISOString().slice(0, 10)
30+
}

blog/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
# Blog <a href="/feed.xml"><Badge type="info" text="RSS" /></a>
22

3-
- `2026-01-01` [Assert and Expect](./assert-and-expect.md)
4-
- `2025-11-07` [Filters](./filters.md)
5-
- `2025-10-30` [Khinkali](./khinkali.md)
3+
<BlogPosts folder="/blog/" />

ru/blog/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
# Блог <a href="/ru/feed.xml"><Badge type="info" text="RSS" /></a>
22

3-
- `2026-01-01` [Assert и Expect](./assert-and-expect.md)
4-
- `2025-11-07` [Фильтры](./filters.md)
5-
- `2025-10-30` [Хинкали](./khinkali.md)
3+
<BlogPosts folder="/ru/blog/" />

0 commit comments

Comments
 (0)