Skip to main content

yggdrasil/components/comments/
card.rs

1//! 评论卡片外壳组件
2//!
3//! `CommentItem`(已审核)与 `PendingCommentItem`(待审核)共享的卡片骨架:
4//! 深度缩进(孤儿评论归零、`--comment-indent` 阶梯、子评论左边框)、
5//! 头像 + 内容两栏布局、作者名/时间头部行。两个调用方只负责各自的差异部分
6//! (作者徽章、状态徽章、时间展示、正文 HTML、正文下方的附加区域)。
7
8use leptos::prelude::*;
9
10use crate::components::ui::UserAvatar;
11
12/// 评论卡片外壳组件。
13///
14/// Props:
15/// - `depth`:归一化后的嵌套深度(孤儿评论已由调用方按 0 处理)
16/// - `muted`:是否降低整体透明度展示(待审核评论用,缺省 `false`)
17/// - `avatar_url` / `author_name`:头像 URL 与无障碍 alt 文本
18/// - `author_element`:作者名展示节点(链接或纯文本,由调用方根据 `author_url` 构建)
19/// - `author_badge`:作者名与分隔符之间的徽章(如已审核评论的"作者"标签);
20///   无需展示时传 `().into_any()`
21/// - `timestamp`:时间展示节点(由调用方构建)
22/// - `status_badge`:时间之后的状态徽章(如待审核评论的"审核中"标签);
23///   无需展示时传 `().into_any()`
24/// - `content_html`:已渲染为安全 HTML 的评论正文
25/// - `content_extra_class`:正文容器附加 CSS 类(已审核评论需额外挂 `md-content`
26///   以命中全局 Markdown 排版/代码高亮 CSS 作用域,缺省空串)
27/// - `children`:正文下方的附加区域(如已审核评论的回复按钮与回复表单)
28///
29/// 样式见 `styles/components/comments.css`:顶层评论之间以发丝线分隔,回复左侧一条
30/// 细线并按 `--comment-indent` 缩进。
31#[component]
32pub fn CommentCardShell(
33    depth: i32,
34    #[prop(optional)] muted: bool,
35    #[prop(into)] avatar_url: String,
36    #[prop(into)] author_name: String,
37    author_element: AnyView,
38    author_badge: AnyView,
39    timestamp: AnyView,
40    status_badge: AnyView,
41    #[prop(into)] content_html: String,
42    #[prop(optional)] content_extra_class: &'static str,
43    #[prop(optional)] children: Option<Children>,
44) -> impl IntoView {
45    let mut class = String::from("comment");
46    if depth > 0 {
47        class.push_str(" is-child");
48    }
49    if muted {
50        class.push_str(" is-pending");
51    }
52    // 回复按层级缩进,五层后不再加深,深层回复不至于被挤到最右。
53    let style = (depth > 1).then(|| format!("--comment-indent: {};", depth.min(5) - 1));
54
55    view! {
56        <div class=class style=style>
57            <UserAvatar name=author_name avatar_url=Some(avatar_url) class="comment-avatar"/>
58            <div class="comment-main">
59                <div class="comment-head">
60                    {author_element}
61                    {author_badge}
62                    {timestamp}
63                    {status_badge}
64                </div>
65                <div
66                    class=format!("comment-body {content_extra_class}")
67                    inner_html=content_html
68                ></div>
69                {children.map(|children| children())}
70            </div>
71        </div>
72    }
73}