This commit is contained in:
@ -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));
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
---
|
||||
import '../assets/style.css'
|
||||
import '../assets/fonts.css'
|
||||
import 'katex/dist/katex.min.css'
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
|
||||
35
src/lib/apis/legacy/blog.ts
Normal file
35
src/lib/apis/legacy/blog.ts
Normal 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
61
src/lib/markdown.ts
Normal 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)
|
||||
}
|
||||
23
src/pages/blogs/[blog_id].astro
Normal file
23
src/pages/blogs/[blog_id].astro
Normal 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} />
|
||||
Reference in New Issue
Block a user