建站
Sanity 开发博客使用 markdown 编辑文章
魔改 cali.so 博客项目 (原项目只支持 blockContent 模式编辑文章),实现用 markdown 编辑文章
3,928次点击10分钟阅读
提示:若不想看教程可以直接 fork 我二开的仓库 next-blog
效果图
实现
- sanity-plugin-markdown 插件拓展 markdown 编辑功能
- react-markdown 将 markdown 渲染为 React 组件
- 缺陷:不能使用行内评论,替代方案使用 Twikoo 评论插件
步骤
部分代码有更新,以仓库最新为准 next-blog
a) 安装依赖
pnpm add sanity-plugin-markdown unified unist-util-visit remark-gfm remark-html remark-parse rehype-slug rehype-raw rehype-highlight
b) 修改代码
sanity\schemas\post.ts
export const Post = z.object({
_id: z.string(),
title: z.string(),
slug: z.string(),
mainImage: z.object({
_ref: z.string(),
asset: z.object({
url: z.string(),
lqip: z.string().optional(),
dominant: z
.object({
background: z.string(),
foreground: z.string(),
})
.optional(),
}),
}),
publishedAt: z.string(),
description: z.string(),
categories: z.array(z.string()).optional(),
body: z.any(),
markdown: z.string(),
readingTime: z.number(),
mood: z.enum(['happy', 'sad', 'neutral']),
})
// export default defineType下新增
defineField({
type: 'markdown',
title: 'markdown内容',
name: 'markdown',
}),
sanity\queries.ts
// export const getBlogPostQuery里新增
export const getBlogPostQuery = groq`
*[_type == "post" && slug.current == $slug && !(_id in path("drafts.**"))][0] {
_id,
title,
"slug": slug.current,
"categories": categories[]->title,
description,
publishedAt,
readingTime,
markdown,
mood,
body[] {
...,
_type == "image" => {
"url": asset->url,
"lqip": asset->metadata.lqip,
"dimensions": asset->metadata.dimensions,
...
}
},
"headings": body[length(style) == 2 && string::startsWith(style, "h")],
mainImage {
_ref,
asset->{
url,
"lqip": metadata.lqip
}
},
"related": *[_type == "post" && slug.current != $slug && count(categories[@._ref in ^.^.categories[]._ref]) > 0] | order(publishedAt desc, _createdAt desc) [0..2] {
_id,
title,
"slug": slug.current,
"categories": categories[]->title,
publishedAt,
readingTime,
mainImage {
_ref,
asset->{
url,
"lqip": metadata.lqip,
"dominant": metadata.palette.dominant
}
},
}
}`
app\(main)\blog\BlogPostPage.tsx
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import rehypeSlug from 'rehype-slug'
import rehypeHighlight from 'rehype-highlight'
import rehypeRaw from 'rehype-raw'
import 'highlight.js/styles/atom-one-dark.css'
...
<Prose className="mt-8">
{/* <PostPortableText value={post.body} /> */}
<Markdown
remarkPlugins={[remarkGfm]}
// @ts-expect-error
rehypePlugins={[rehypeSlug, rehypeRaw, rehypeHighlight]}
components={{ code: Code }}
>
{post.markdown}
</Markdown>
</Prose>