Skip to main content

yggdrasil/components/comments/
pending_item.rs

1//! 待审核评论项组件
2//!
3//! 展示用户刚提交、尚未通过审核的评论占位项,
4//! 视觉上使用较低的透明度并标注"审核中"状态。
5
6use dioxus::prelude::*;
7
8use crate::utils::comment_storage::{render_pending_content, PendingComment};
9use crate::utils::time::format_relative_time_iso;
10
11/// 待审核评论项组件。
12///
13/// Props:
14/// - `comment`:待审核评论数据
15/// - `post_id`:所属文章 ID(当前未使用,保留用于未来扩展)
16///
17/// 展示内容包括:作者头像/链接、基于创建时间动态计算的相对时间、审核中徽章、Markdown 渲染内容。
18/// 深度最大展示 6 层缩进,孤儿评论深度会被修正为 0。
19#[component]
20#[allow(unused_variables)]
21pub fn PendingCommentItem(comment: PendingComment, post_id: i32) -> Element {
22    // 孤儿评论(parent_id 为 None 但 depth > 0)按顶层展示
23    let depth = if comment.parent_id.is_none() && comment.depth > 0 {
24        0
25    } else {
26        comment.depth
27    };
28
29    let indent = depth.min(6) * 24;
30    let content_html = render_pending_content(&comment.content_md);
31    // 基于创建时间实时计算相对时间,避免"刚刚"永久显示。
32    let relative_time = format_relative_time_iso(&comment.created_at);
33
34    // 作者名展示为链接或普通文本
35    let author_element = match &comment.author_url {
36        Some(url) if !url.is_empty() => rsx! {
37            a {
38                href: "{url}",
39                rel: "nofollow noopener",
40                target: "_blank",
41                class: "font-medium text-paper-primary hover:text-paper-accent transition-colors",
42                "{comment.author_name}"
43            }
44        },
45        _ => rsx! {
46            span { class: "font-medium text-paper-primary", "{comment.author_name}" }
47        },
48    };
49
50    rsx! {
51        div { class: "py-4 opacity-70", style: "margin-left: {indent}px",
52
53            div { class: "flex gap-3",
54                img {
55                    src: "{comment.avatar_url}",
56                    alt: "{comment.author_name} 的头像",
57                    loading: "lazy",
58                    decoding: "async",
59                    class: "w-8 h-8 rounded-full shrink-0 mt-0.5 bg-gray-200 dark:bg-gray-800",
60                }
61
62                div { class: "flex-1 min-w-0",
63                    div { class: "flex items-center gap-1.5 text-sm mb-1.5 flex-wrap",
64                        {author_element}
65                        span { class: "text-paper-tertiary", "·" }
66                        span {
67                            class: "text-paper-tertiary",
68                            title: "{comment.created_at}",
69                            "{relative_time}"
70                        }
71                        span { class: "inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400",
72                            "审核中"
73                        }
74                    }
75
76                    div {
77                        class: "prose prose-sm dark:prose-invert max-w-none text-paper-secondary",
78                        dangerous_inner_html: "{content_html}",
79                    }
80                }
81            }
82        }
83    }
84}