diff --git a/astro.config.ts b/astro.config.ts
index a877751..01c188b 100644
--- a/astro.config.ts
+++ b/astro.config.ts
@@ -119,6 +119,7 @@ export default defineConfig({
'className': ['anchor-icon'],
'data-pagefind-ignore': true,
},
+ // TODO: Switch # to icon
children: [
{
type: 'text',
diff --git a/package.json b/package.json
index 2a9919c..be5def1 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"astro-compress": "^2.3.6",
"astro-robots-txt": "^1.0.0",
"astro-seo": "^0.8.4",
+ "markdown-it": "^14.1.0",
"overlayscrollbars": "^2.10.1",
"photoswipe": "^5.4.4",
"rehype-autolink-headings": "^7.1.0",
@@ -46,6 +47,7 @@
"devDependencies": {
"@antfu/eslint-config": "^3.14.0",
"@types/hast": "^3.0.4",
+ "@types/markdown-it": "^14.1.2",
"@types/mdast": "^4.0.4",
"@types/node": "^22.10.6",
"@types/sanitize-html": "^2.13.0",
diff --git a/src/content/config.ts b/src/content/config.ts
new file mode 100644
index 0000000..95bddd5
--- /dev/null
+++ b/src/content/config.ts
@@ -0,0 +1,18 @@
+import { defineCollection, z } from 'astro:content'
+
+const postsCollection = defineCollection({
+ schema: z.object({
+ title: z.string(),
+ published: z.date(),
+ updated: z.date().optional(),
+ draft: z.boolean().optional().default(false),
+ description: z.string().optional().default(''),
+ tags: z.array(z.string()).optional().default([]),
+ lang: z.string().optional().default(''),
+ slug: z.string().optional().default(''),
+ pin: z.boolean().optional().default(false),
+ }),
+})
+export const collections = {
+ posts: postsCollection,
+}
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index 05587c2..5d44e87 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -6,6 +6,14 @@
Astro Basics
+
+
+
diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts
new file mode 100644
index 0000000..e62a6e9
--- /dev/null
+++ b/src/pages/rss.xml.ts
@@ -0,0 +1,33 @@
+import type { APIContext } from 'astro'
+import themeConfig from '@/config'
+import rss from '@astrojs/rss'
+import { getCollection } from 'astro:content'
+import MarkdownIt from 'markdown-it'
+import sanitizeHtml from 'sanitize-html'
+import
+
+const parser = new MarkdownIt()
+const { title, description, url } = themeConfig.site
+const { language } = themeConfig.global
+
+export async function GET(_context: APIContext) {
+ const posts = await getCollection('blog', ({ data }) => {
+ return !data.draft // 只包含非草稿文章
+ })
+
+ return rss({
+ title,
+ description,
+ site: url,
+ items: posts.map(post => ({
+ title: post.data.title,
+ pubDate: post.data.published, // 使用 published 而不是 pubDate
+ description: post.data.description,
+ link: `/posts/${post.slug}/`,
+ content: sanitizeHtml(parser.render(post.body), {
+ allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
+ }),
+ })),
+ customData: `${language}`,
+ })
+}
diff --git a/src/utils/content.config.ts b/src/utils/content.config.ts
new file mode 100644
index 0000000..3090423
--- /dev/null
+++ b/src/utils/content.config.ts
@@ -0,0 +1,50 @@
+import type { CollectionEntry } from 'astro:content'
+import { getCollection } from 'astro:content'
+import MarkdownIt from 'markdown-it'
+import sanitizeHtml, { type Tag } from 'sanitize-html'
+
+export type Post = CollectionEntry<'posts'>
+
+export async function getPosts(isArchivePage = false) {
+ const posts = await getCollection('posts', ({ data }) => {
+ return import.meta.env.DEV || !data.draft
+ })
+
+ // 按发布日期降序排序
+ return posts.sort((a, b) => b.data.published.valueOf() - a.data.published.valueOf())
+}
+
+// 获取所有标签及其对应的文章
+export async function getPostsByTags() {
+ const posts = await getPosts()
+ const tagMap = new Map()
+
+ posts.forEach((post) => {
+ post.data.tags?.forEach((tag) => {
+ if (!tagMap.has(tag)) {
+ tagMap.set(tag, [])
+ }
+ tagMap.get(tag)?.push(post)
+ })
+ })
+
+ return tagMap
+}
+
+// 获取指定标签的所有文章
+export async function getPostsByTag(tag: string) {
+ const posts = await getPosts()
+ return posts.filter(post => post.data.tags?.includes(tag))
+}
+
+// 获取所有标签列表
+export async function getAllTags() {
+ const posts = await getPosts()
+ const tags = new Set()
+
+ posts.forEach((post) => {
+ post.data.tags?.forEach(tag => tags.add(tag))
+ })
+
+ return Array.from(tags)
+}
diff --git a/tsconfig.json b/tsconfig.json
index f660573..8aff919 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,9 @@
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
- }
+ },
+ "allowJs": false,
+ "strictNullChecks": true
},
"include": [
".astro/types.d.ts",