feat(评论): 添加Markdown渲染和样式支持
- 引入marked和xss库处理评论内容的Markdown渲染和XSS过滤 - 添加CSS样式支持评论内容的标题、列表、代码块等Markdown元素显示
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,5 +1,7 @@
|
|||||||
import { Context } from 'hono';
|
import { Context } from 'hono';
|
||||||
import { UAParser } from 'ua-parser-js';
|
import { UAParser } from 'ua-parser-js';
|
||||||
|
import { marked } from 'marked';
|
||||||
|
import xss from 'xss';
|
||||||
import { Bindings } from '../../bindings';
|
import { Bindings } from '../../bindings';
|
||||||
import {
|
import {
|
||||||
sendCommentNotification,
|
sendCommentNotification,
|
||||||
@@ -67,11 +69,12 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
|||||||
`).run();
|
`).run();
|
||||||
|
|
||||||
// 3. 准备数据
|
// 3. 准备数据
|
||||||
const contentText = checkContent(rawContent);
|
const cleanedContent = checkContent(rawContent);
|
||||||
|
const contentText = cleanedContent;
|
||||||
const author = checkContent(rawAuthor);
|
const author = checkContent(rawAuthor);
|
||||||
|
|
||||||
// Markdown 渲染与 XSS 过滤
|
// Markdown 渲染与 XSS 过滤
|
||||||
const html = await marked.parse(rawContent, { async: true });
|
const html = await marked.parse(cleanedContent, { async: true });
|
||||||
const contentHtml = xss(html, {
|
const contentHtml = xss(html, {
|
||||||
whiteList: {
|
whiteList: {
|
||||||
...xss.whiteList,
|
...xss.whiteList,
|
||||||
|
|||||||
@@ -396,6 +396,101 @@
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content h1,
|
||||||
|
.cwd-comment-content h2,
|
||||||
|
.cwd-comment-content h3,
|
||||||
|
.cwd-comment-content h4,
|
||||||
|
.cwd-comment-content h5,
|
||||||
|
.cwd-comment-content h6 {
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content h1 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content h2 {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content h3 {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content ul,
|
||||||
|
.cwd-comment-content ol {
|
||||||
|
padding-left: 1.7em;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content li + li {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content code {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
|
background: var(--cwd-bg-secondary, #f6f8fa);
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content pre {
|
||||||
|
padding: 12px;
|
||||||
|
margin: 12px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
background: var(--cwd-bg-secondary, #f6f8fa);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content pre code {
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content blockquote {
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-left: 4px solid var(--cwd-border, #d0d7de);
|
||||||
|
color: var(--cwd-text-secondary, #6e7781);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content hr {
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid var(--cwd-border-light, #eaeef2);
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content th,
|
||||||
|
.cwd-comment-content td {
|
||||||
|
border: 1px solid var(--cwd-border, #d0d7de);
|
||||||
|
padding: 6px 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content th {
|
||||||
|
background: var(--cwd-bg-secondary, #f6f8fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cwd-comment-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.cwd-comment-actions {
|
.cwd-comment-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -617,4 +712,4 @@
|
|||||||
|
|
||||||
.cwd-comments-container::-webkit-scrollbar-thumb:hover {
|
.cwd-comments-container::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--cwd-text-secondary);
|
background: var(--cwd-text-secondary);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user