"use client"; import Link from "next/link"; import styles from "./community.module.css"; import { renderCommunityMarkdown } from "./renderMarkdown"; export type CommunityAttachment = { url: string; alt?: string; }; export type CommunityComment = { id: string; memo_id: string; user_id: string; content: string; created?: string; updated?: string; }; export type CommunityMemo = { id: string; user_id: string; content: string; pinned?: boolean; visibility?: string; state?: "NORMAL" | "ARCHIVED"; created?: string; updated?: string; create_time?: string; update_time?: string; display_time?: string; tags?: string[]; attachments?: CommunityAttachment[]; comment_count?: number; reaction_count?: number; liked_by_me?: boolean; comments?: CommunityComment[]; }; export function parseTags(content: string): string[] { const matches = content.match(/#[\w\u4e00-\u9fa5]+/g) || []; return [...new Set(matches.map((match) => match.slice(1)))]; } export function formatCommunityTime(iso?: string): string { if (!iso) { return ""; } try { const date = new Date(iso); const diff = Date.now() - date.getTime(); if (diff < 60_000) { return "刚刚"; } if (diff < 3_600_000) { return `${Math.floor(diff / 60_000)} 分钟前`; } if (diff < 86_400_000) { return `${Math.floor(diff / 3_600_000)} 小时前`; } if (diff < 604_800_000) { return `${Math.floor(diff / 86_400_000)} 天前`; } return date.toLocaleDateString("zh-CN", { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); } catch { return ""; } } export function maskCommunityUserId(value: string): string { if (!value) { return "匿名成员"; } if (/^user\d+$/i.test(value)) { return `成员 ${value.slice(-4)}`; } return value.length > 12 ? `${value.slice(0, 8)}...` : value; } export function buildCommunityAvatarText(value: string): string { if (!value) { return "匿"; } if (/^user\d+$/i.test(value)) { return value.slice(-2); } return value.slice(0, 2).toUpperCase(); } type CommunityMemoCardProps = { memo: CommunityMemo; isOwner?: boolean; actionDisabled?: boolean; hideDetailLink?: boolean; onDelete?: (id: string) => void; onPinToggle?: (id: string, pinned: boolean) => void; onReactionToggle?: (id: string) => void; onArchiveToggle?: (id: string, nextState: "NORMAL" | "ARCHIVED") => void; onTagClick?: (tag: string) => void; }; export function CommunityMemoCard({ memo, isOwner, actionDisabled = false, hideDetailLink = false, onDelete, onPinToggle, onReactionToggle, onArchiveToggle, onTagClick, }: CommunityMemoCardProps) { const tags = memo.tags?.length ? memo.tags : parseTags(memo.content); const attachments = memo.attachments ?? []; const nextArchiveState = memo.state === "ARCHIVED" ? "NORMAL" : "ARCHIVED"; return (
{buildCommunityAvatarText(memo.user_id)}
{maskCommunityUserId(memo.user_id)} {formatCommunityTime( memo.display_time || memo.created || memo.updated || memo.create_time || memo.update_time )}
{memo.pinned ? 置顶 : null} {memo.state === "ARCHIVED" ? 已归档 : null}
{tags.length ? (
{tags.map((tag) => ( ))}
) : null}
赞 {memo.reaction_count ?? 0} 评论 {memo.comment_count ?? 0} {attachments.length ? 附件 {attachments.length} : null}
{onReactionToggle ? ( ) : null} {!hideDetailLink ? ( 查看详情 ) : null} {isOwner && onPinToggle ? ( ) : null} {isOwner && onArchiveToggle ? ( ) : null} {isOwner && onDelete ? ( ) : null}
); }