This commit is contained in:
anghunk
2026-03-26 10:04:41 +08:00
14 changed files with 135 additions and 52 deletions

View File

@@ -34,6 +34,7 @@
},
"dependencies": {
"dompurify": "^3.3.1",
"marked": "^17.0.1"
"marked": "^17.0.1",
"node-emoji": "^2.2.0"
}
}
}

View File

@@ -5,6 +5,7 @@
import { Component } from './Component.js';
import { ReplyEditor } from './ReplyEditor.js';
import { formatRelativeTime } from '@/utils/date.js';
import { replaceEmojiInHtml } from '@/utils/markdown.js';
export class CommentItem extends Component {
// 防抖缓存,防止连续点击
@@ -202,7 +203,7 @@ export class CommentItem extends Component {
// 设置评论内容的 TEXT
const contentEl = root.querySelector('.cwd-comment-content');
if (contentEl) {
contentEl.innerHTML = comment.contentHtml;
contentEl.innerHTML = replaceEmojiInHtml(comment.contentHtml);
}
// 创建回复编辑器
@@ -371,8 +372,12 @@ export class CommentItem extends Component {
likedComments.add(commentId);
this.saveLikedComments(likedComments);
this.props.onLikeComment(commentId, true);
} else {
// 已点赞,执行取消点赞
likedComments.delete(commentId);
this.saveLikedComments(likedComments);
this.props.onLikeComment(commentId, false);
}
// 已点赞则不做任何操作
}
/**

View File

@@ -466,8 +466,14 @@ export class CWDComments {
onUpdateReplyContent: (content) => this.store.updateReplyContent(content),
onClearReplyError: () => this.store.clearReplyError(),
replyPlaceholder: this.config.commentPlaceholder,
onPrevPage: () => this.store.goToPage(state.pagination.page - 1),
onNextPage: () => this.store.goToPage(state.pagination.page + 1),
onPrevPage: () => {
const currentState = this.store.store.getState();
this.store.goToPage(currentState.pagination.page - 1);
},
onNextPage: () => {
const currentState = this.store.store.getState();
this.store.goToPage(currentState.pagination.page + 1);
},
onGoToPage: (page) => this.store.goToPage(page),
onLikeComment: (commentId, isLike) => {
if (this.store && typeof this.store.likeComment === 'function') {

View File

@@ -660,6 +660,10 @@
color: var(--cwd-primary, #0969da);
}
.cwd-comment-like-button-liked {
color: var(--cwd-primary, #0969da);
}
.cwd-comment-like-icon-wrapper {
display: inline-flex;
align-items: center;

View File

@@ -1,5 +1,6 @@
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import * as emoji from 'node-emoji';
// 配置 marked
try {
@@ -11,6 +12,30 @@ try {
console.error('Failed to configure marked:', e);
}
/**
* 替换文本中的 emoji 代码为实际 emoji
* @param {string} text 包含 emoji 代码的文本
* @returns {string} 替换后的文本
*/
function replaceEmoji(text) {
if (!text) return text;
try {
return emoji.emojify(text);
} catch (e) {
return text;
}
}
/**
* 替换 HTML 中的 emoji 代码为实际 emoji
* @param {string} html 包含 emoji 代码的 HTML
* @returns {string} 替换后的 HTML
*/
export function replaceEmojiInHtml(html) {
if (!html) return html;
return replaceEmoji(html);
}
/**
* 渲染 Markdown 为 HTML并进行净化
* @param {string} content Markdown 内容
@@ -19,7 +44,8 @@ try {
export function renderMarkdown(content) {
if (!content) return '';
try {
const html = marked.parse(content);
const contentWithEmoji = replaceEmoji(content);
const html = marked.parse(contentWithEmoji);
// marked.parse can return a Promise if async is enabled, but we are using sync mode
// Just in case, handle potential Promise (though unlikely with current config)
if (html instanceof Promise) {