Skip to main content

yggdrasil/components/skeletons/
home_skeleton.rs

1//! 首页骨架屏:与「书桌」布局逐块对齐,数据到达后不跳动。
2//! 最新一篇面板的右栏固定 6 行目录占位。
3
4use leptos::prelude::*;
5
6use crate::components::skeletons::atoms::SkeletonBox;
7
8/// 目录占位每行的宽度,错落排布更像真实标题。
9const OUTLINE_WIDTHS: [&str; 6] = [
10    "width: 70%",
11    "width: 90%",
12    "width: 60%",
13    "width: 85%",
14    "width: 75%",
15    "width: 50%",
16];
17/// 索引每行标题的宽度。
18const ROW_WIDTHS: [&str; 5] = [
19    "width: 70%",
20    "width: 55%",
21    "width: 80%",
22    "width: 62%",
23    "width: 74%",
24];
25
26#[component]
27pub fn HomeSkeleton(#[prop(default = 1)] current_page: i32) -> impl IntoView {
28    if current_page > 1 {
29        return view! {
30            <div class="home home-paged" role="status" aria-label="正在加载文章">
31                <header class="home-paged-header">
32                    <SkeletonBox class="h-4 w-20"/>
33                    <SkeletonBox class="home-skeleton-title w-40"/>
34                    <SkeletonBox class="h-4 w-16"/>
35                </header>
36                <HomePostsSkeleton current_page=current_page/>
37            </div>
38        }
39        .into_any();
40    }
41    view! {
42        <div class="home" role="status" aria-label="正在加载首页">
43            <div class="home-hero">
44                <SkeletonBox class="h-3 w-56 max-w-full"/>
45                <SkeletonBox class="home-skeleton-title mt-6 w-[22rem] max-w-full"/>
46                <SkeletonBox class="home-skeleton-title mt-3 w-[17rem] max-w-full"/>
47                <SkeletonBox class="h-3.5 mt-6 w-[28rem] max-w-full"/>
48                <SkeletonBox class="home-skeleton-composer mt-9"/>
49            </div>
50            <div class="home-section">
51                <SkeletonBox class="h-3 w-16 mb-4"/>
52                <div class="home-latest">
53                    <div class="home-latest-main">
54                        <SkeletonBox class="h-3 w-40"/>
55                        <SkeletonBox class="h-7 mt-4 w-4/5"/>
56                        <SkeletonBox class="h-3 mt-4 w-full"/>
57                        <SkeletonBox class="h-3 mt-2.5 w-3/4"/>
58                    </div>
59                    <div class="home-latest-outline">
60                        <SkeletonBox class="h-3 w-16 mb-3"/>
61                        <div class="flex flex-col gap-3">
62                            {OUTLINE_WIDTHS
63                                .iter()
64                                .map(|width| view! { <SkeletonBox class="h-3" style=*width/> })
65                                .collect_view()}
66                        </div>
67                    </div>
68                </div>
69            </div>
70            <HomePostsSkeleton current_page=current_page/>
71        </div>
72    }
73    .into_any()
74}
75
76/// 文章索引占位:月份分隔与五行条目。
77#[component]
78pub fn HomePostsSkeleton(current_page: i32) -> impl IntoView {
79    view! {
80        <div class="home-index" aria-hidden="true">
81            {(current_page == 1)
82                .then(|| {
83                    view! {
84                        <div class="home-index-heading">
85                            <SkeletonBox class="h-5 w-28"/>
86                            <SkeletonBox class="h-4 w-12"/>
87                        </div>
88                    }
89                })}
90            <div class="home-month">
91                <SkeletonBox class="home-month-label h-3 w-16"/>
92                {ROW_WIDTHS
93                    .iter()
94                    .map(|width| {
95                        view! {
96                            <div class="home-row home-row-skeleton">
97                                <SkeletonBox class="h-3 w-10"/>
98                                <div>
99                                    <SkeletonBox class="h-4" style=*width/>
100                                    <SkeletonBox class="h-3 mt-2 w-[90%]"/>
101                                </div>
102                                <SkeletonBox class="home-row-meta h-3 w-14"/>
103                            </div>
104                        }
105                    })
106                    .collect_view()}
107            </div>
108        </div>
109    }
110}