feat: 完善表情选择与评论富文本展示
发帖编辑器支持 OwO 贴纸;评论区复用文章列表、段落与代码块阅读态,并优化表情面板间距与悬停反馈。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
import { POST_CONTENT_PURIFY_CONFIG } from './postContent';
|
||||
import { enhanceCodeBlocks } from './enhanceCodeBlocks';
|
||||
|
||||
/** 转义 HTML 并保留换行 */
|
||||
function escapeWithBreaks(text: string): string {
|
||||
@@ -60,11 +61,15 @@ function processMentionsInHtml(html: string): string {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/** 渲染评论内容:HTML 净化 + @提及高亮,兼容旧版纯文本 */
|
||||
/** 渲染评论内容:HTML 净化 + @提及高亮 + 代码块阅读态,兼容旧版纯文本 */
|
||||
export function renderCommentContent(content: string): string {
|
||||
if (isHtmlContent(content)) {
|
||||
const sanitized = DOMPurify.sanitize(content, POST_CONTENT_PURIFY_CONFIG) as string;
|
||||
return processMentionsInHtml(sanitized);
|
||||
const withMentions = processMentionsInHtml(sanitized);
|
||||
const doc = new DOMParser().parseFromString(`<div id="j13-comment-root">${withMentions}</div>`, 'text/html');
|
||||
const root = doc.getElementById('j13-comment-root') ?? doc.body;
|
||||
enhanceCodeBlocks(root);
|
||||
return root.innerHTML;
|
||||
}
|
||||
return highlightMentions(content);
|
||||
}
|
||||
|
||||
@@ -177,3 +177,44 @@ export function enhanceCodeBlocks(root: ParentNode): void {
|
||||
if (display.lineNumbers) pre.classList.add('md-codeblock__pre--lines');
|
||||
});
|
||||
}
|
||||
|
||||
const CODE_FOLD_SHORT_LINES = 5;
|
||||
|
||||
/**
|
||||
* 阅读态代码块:折叠 / 复制。由帖子与评论共用,点击已处理时返回 true。
|
||||
*/
|
||||
export async function handleMdCodeBlockUiClick(target: EventTarget | null): Promise<boolean> {
|
||||
if (!(target instanceof Element)) return false;
|
||||
|
||||
const foldBtn = target.closest<HTMLElement>('[data-code-fold]');
|
||||
if (foldBtn) {
|
||||
const block = foldBtn.closest('.md-codeblock');
|
||||
if (!block) return true;
|
||||
const collapsed = block.classList.toggle('md-codeblock--collapsed');
|
||||
const lineCount = parseInt(block.getAttribute('data-line-count') || '0', 10)
|
||||
|| block.querySelectorAll('.md-code-line').length
|
||||
|| 1;
|
||||
if (collapsed && lineCount <= CODE_FOLD_SHORT_LINES) block.classList.add('md-codeblock--short');
|
||||
else block.classList.remove('md-codeblock--short');
|
||||
foldBtn.textContent = collapsed ? '展开' : '收起';
|
||||
return true;
|
||||
}
|
||||
|
||||
const copyBtn = target.closest<HTMLElement>('[data-code-copy]');
|
||||
if (!copyBtn) return false;
|
||||
|
||||
const block = copyBtn.closest('.md-codeblock');
|
||||
const bodies = block?.querySelectorAll('.md-code-line__body');
|
||||
const text = bodies && bodies.length
|
||||
? [...bodies].map(el => el.textContent ?? '').join('\n')
|
||||
: (block?.querySelector('pre')?.textContent ?? '');
|
||||
await navigator.clipboard.writeText(text);
|
||||
const prev = copyBtn.textContent;
|
||||
copyBtn.textContent = '已复制';
|
||||
copyBtn.classList.add('is-copied');
|
||||
window.setTimeout(() => {
|
||||
copyBtn.textContent = prev || '复制';
|
||||
copyBtn.classList.remove('is-copied');
|
||||
}, 1600);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user