Update comment tags and hashtag payload

This commit is contained in:
LeonspaceX
2026-01-26 17:56:48 +08:00
parent f6d9521f80
commit 929ff68f50
2 changed files with 64 additions and 1 deletions

View File

@@ -250,6 +250,17 @@ export interface PostCommentResponse {
export const postComment = async (commentData: PostCommentRequest): Promise<PostCommentResponse> => { export const postComment = async (commentData: PostCommentRequest): Promise<PostCommentResponse> => {
try { try {
const identity = await get_id_token(); const identity = await get_id_token();
const hashtopic: string[] = [];
const regex = /#\S+/g;
const matches = commentData.content.match(regex);
if (matches) {
matches.forEach(tag => {
const cleanTag = tag.substring(1);
if (!hashtopic.includes(cleanTag)) {
hashtopic.push(cleanTag);
}
});
}
const response = await fetch('/api/comment', { const response = await fetch('/api/comment', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -257,6 +268,7 @@ export const postComment = async (commentData: PostCommentRequest): Promise<Post
}, },
body: JSON.stringify({ body: JSON.stringify({
...commentData, ...commentData,
hashtopic,
identity, identity,
}), }),
}); });

View File

@@ -16,6 +16,8 @@ import { Dismiss24Regular, ArrowReply24Regular } from '@fluentui/react-icons';
import { getComments, postComment } from '../api'; import { getComments, postComment } from '../api';
import type { Comment as CommentType } from '../api'; import type { Comment as CommentType } from '../api';
import { useLayout } from '../context/LayoutContext'; import { useLayout } from '../context/LayoutContext';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
const useStyles = makeStyles({ const useStyles = makeStyles({
container: { container: {
@@ -85,8 +87,43 @@ const useStyles = makeStyles({
height: '40px', height: '40px',
fontSize: '16px', fontSize: '16px',
}, },
tag: {
color: tokens.colorBrandForeground1,
textDecoration: 'none',
},
}); });
// 自定义 remark 插件,用于高亮 #tag
const remarkTagPlugin = () => {
return (tree: any) => {
const transformNode = (node: any, inLink = false) => {
if (node.type === 'link') inLink = true;
if (node.children) {
node.children = node.children.flatMap((child: any) => {
if (child.type === 'text' && !inLink) {
const parts = child.value.split(/(#\S+)/g);
return parts.map((part: string) => {
if (part.match(/^#\S+$/)) {
return {
type: 'link',
url: 'tag:' + part,
children: [{ type: 'text', value: part }]
};
}
if (part === "") return [];
return { type: 'text', value: part };
}).flat();
}
return transformNode(child, inLink);
});
}
return node;
};
transformNode(tree);
};
};
interface CommentSectionProps { interface CommentSectionProps {
postId: number; postId: number;
} }
@@ -188,7 +225,21 @@ const CommentSection: React.FC<CommentSectionProps> = ({ postId }) => {
<div className={styles.commentHeader}> <div className={styles.commentHeader}>
<Text className={styles.nickname}>{comment.nickname}</Text> <Text className={styles.nickname}>{comment.nickname}</Text>
</div> </div>
<Text>{comment.content}</Text> <div style={{ whiteSpace: 'pre-wrap' }}>
<ReactMarkdown
remarkPlugins={[remarkGfm, remarkTagPlugin]}
components={{
a: ({ node, ...props }) => {
if (props.href && props.href.startsWith('tag:')) {
return <span className={styles.tag}>{props.children}</span>;
}
return <a {...props} />;
},
}}
>
{comment.content}
</ReactMarkdown>
</div>
<div className={styles.commentFooter}> <div className={styles.commentFooter}>
<Tooltip content="回复" relationship="label"> <Tooltip content="回复" relationship="label">
<div <div