添加 Markdown 渲染
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-03-27 15:11:41 +08:00
parent b4298602bf
commit eb0be5ebca
7 changed files with 268 additions and 8 deletions

View File

@ -5,20 +5,32 @@
/* == 主题色 == */
:root {
color-scheme: light dark;
color-scheme: light dark;
--color-bg-0: light-dark(oklch(95% 0 0), oklch(30% 0.02 270));
--color-fg-0: light-dark(oklch(25% 0.02 270), oklch(90% 0.02 270));
--color-bg-0: light-dark(oklch(95% 0 0), oklch(30% 0.02 270));
--color-fg-0: light-dark(oklch(25% 0.02 270), oklch(90% 0.02 270));
--color-link: light-dark(oklch(40% 0.2 270), oklch(80% 0.2 270));
--color-link: light-dark(oklch(40% 0.2 270), oklch(80% 0.2 270));
}
/* == 页面设置 == */
html,
body {
margin: 0;
padding: 0;
margin: 0;
padding: 0;
background-color: var(--color-bg-0);
color: var(--color-fg-0);
background-color: var(--color-bg-0);
color: var(--color-fg-0);
}
/* == 支持 Shiki 的高亮 == */
pre.shiki code {
font-family: var(--font-mono);
font-size: .9rem;
}
pre.shiki,
pre.shiki span {
color: light-dark(var(--shiki-light), var(--shiki-dark));
background-color: light-dark(var(--shiki-light-bg), var(--shiki-dark-bg));
}

View File

@ -1,6 +1,7 @@
---
import '../assets/style.css'
import '../assets/fonts.css'
import 'katex/dist/katex.min.css'
interface Props {
title?: string

View File

@ -0,0 +1,35 @@
import { legacyClient } from '../clients'
export const listBlogs = async ({
page = 1,
limit = 20,
}: {
page?: number
limit?: number
}) => {
const resp = await legacyClient.post('/v1/blog/list', { page, limit })
return resp.data.data as {
id: number
title: string
featured_image: null | {
image_url: string
}
}[]
}
export const getBlog: (
blog_id: number,
) => Promise<null | { title: string; content: string }> = async (
blog_id: number,
) => {
const resp = await legacyClient.get(`/v1/blog/${blog_id}`, {
validateStatus: (status) => status == 200 || status == 404,
})
if (resp.status == 404) {
return null
}
return resp.data as {
title: string
content: string
}
}

61
src/lib/markdown.ts Normal file
View File

@ -0,0 +1,61 @@
import MarkdownIt from 'markdown-it'
import mdKatex from '@traptitech/markdown-it-katex'
import { createHighlighter, type Highlighter } from 'shiki'
let highlighter: Highlighter | null = null
/**
* Markdown 渲染函数。
*
* 为了让客户端和服务端表现相同,所以单独拿出来了一个 Markdown 渲染器。
*/
export async function renderMarkdown(content: string): Promise<string> {
if (highlighter === null) {
highlighter = await createHighlighter({
themes: ['one-light', 'one-dark-pro'],
/* 额...要我自己定义需要的所有语言吗 */
langs: [
'python',
'javascript',
'typescript',
'typst',
'markdown',
'json',
'toml',
'yaml',
'bash',
'c',
'c++',
'rust',
'go',
'zig',
'makefile',
'make',
'nim',
'nix',
'kdl',
'md',
'sh',
],
})
}
const md = new MarkdownIt({
html: true,
linkify: true,
highlight: (code, lang) => {
return highlighter!.codeToHtml(code, {
lang: lang || 'text',
themes: {
light: 'one-light',
dark: 'one-dark-pro',
},
defaultColor: false,
})
},
})
md.use(mdKatex)
return md.render(content)
}

View File

@ -0,0 +1,23 @@
---
import { getBlog } from '../../lib/apis/legacy/blog'
import BaseLayout from '../../layout/BaseLayout.astro'
import { renderMarkdown } from '../../lib/markdown'
export const prerender = false
const { blog_id } = Astro.params
const blog_id_num = parseInt(blog_id)
if (isNaN(blog_id_num) || blog_id_num < 0) {
return Astro.redirect('/404')
}
const blogData = await getBlog(blog_id_num)
if (blogData === null) {
return Astro.redirect('/404')
}
const blogRendered = await renderMarkdown(blogData.content)
---
<BaseLayout set:html={blogRendered} />