Skip to main content

yggdrasil/components/post/
post_meta.rs

1//! 文章元信息组件
2//!
3//! 展示文章发布日期、阅读时长与字数统计。
4
5use leptos::prelude::*;
6
7use crate::models::post::PostHeaderData;
8use crate::utils::time::ymd;
9
10/// 文章元信息组件。
11///
12/// Props:
13/// - `post`:页眉展示所需的最小字段集(P4.2:不携带完整正文)
14///
15/// 日期优先使用发布时间,否则回退到创建时间,用标题字体的旧式数字;阅读时长与字数
16/// 用等宽数字。窄屏下各项整体换行。
17#[component]
18pub(super) fn PostMeta(post: PostHeaderData) -> impl IntoView {
19    let at = post.published_at.unwrap_or(post.created_at);
20    let datetime = ymd(&at, '-');
21    let date = ymd(&at, '.');
22    let words = group_digits(post.word_count);
23    let reading = format!("{} 分钟", post.reading_time);
24    let words = format!("{words} 字");
25
26    view! {
27        <p class="post-meta" aria-label="文章元信息">
28            <time class="post-meta-date" datetime=datetime>{date}</time>
29            <span class="tabular-nums">{reading}</span>
30            <span class="tabular-nums">{words}</span>
31        </p>
32    }
33}
34
35/// 千位分隔:`4866` → `4,866`。
36pub(crate) fn group_digits(n: u32) -> String {
37    let digits = n.to_string();
38    let mut out = String::with_capacity(digits.len() + digits.len() / 3);
39    for (i, c) in digits.chars().enumerate() {
40        if i > 0 && (digits.len() - i).is_multiple_of(3) {
41            out.push(',');
42        }
43        out.push(c);
44    }
45    out
46}
47
48#[cfg(test)]
49mod tests {
50    use super::group_digits;
51
52    #[test]
53    fn groups_thousands() {
54        assert_eq!(group_digits(0), "0");
55        assert_eq!(group_digits(866), "866");
56        assert_eq!(group_digits(4866), "4,866");
57        assert_eq!(group_digits(1_234_567), "1,234,567");
58    }
59}