Skip to main content

yggdrasil/components/skeletons/
atoms.rs

1//! 骨架屏原子组件
2//!
3//! 提供通用的扫光占位块,供各页面骨架屏组合使用。
4
5use leptos::prelude::*;
6
7/// 通用骨架占位块。
8///
9/// Props:
10/// - `class`:Tailwind CSS 类,控制尺寸与形状
11/// - `style`:可选的内联样式字符串
12/// - `animate`:是否带扫光动画(缺省 `true`)。少数骨架屏在切换动画/骨架屏截断
13///   场景需要关闭,避免动画被截断显得突兀。
14///
15/// 外观见 ui.css 的 `.skeleton`:`ink-1` 到 `ink-2` 的柔和扫光,减少动态效果时静止。
16#[component]
17pub fn SkeletonBox(
18    #[prop(into)] class: String,
19    #[prop(optional, into)] style: Option<&'static str>,
20    #[prop(default = true)] animate: bool,
21) -> impl IntoView {
22    view! {
23        <div
24            class=format!("skeleton {class}")
25            data-static=(!animate).then_some("true")
26            style=style.unwrap_or("")
27        ></div>
28    }
29}
30
31/// 后台页面标题行骨架,结构与 `admin_layout::AdminPageHead` 一致。
32/// `title_width` / `subtitle_width` 只传宽度类(如 `"w-20"`、`"w-96 max-w-full"`)。
33/// `actions` 是右侧操作区占位,传闭包:`actions=|| view! { <SkeletonBox class="h-[34px] w-24 rounded-lg"/> }`。
34#[component]
35pub fn AdminPageHeadSkeleton(
36    title_width: &'static str,
37    subtitle_width: &'static str,
38    #[prop(optional)] class: Option<&'static str>,
39    #[prop(optional, into)] actions: Option<ViewFn>,
40) -> impl IntoView {
41    let extra = class.unwrap_or_default();
42    view! {
43        <div class=format!("admin-page-head {extra}")>
44            <div>
45                <SkeletonBox class=format!("h-7 {title_width} rounded-md")/>
46                <SkeletonBox class=format!("h-3.5 {subtitle_width} rounded mt-2")/>
47            </div>
48            {actions.map(|actions| view! { <div class="admin-page-actions">{actions.run()}</div> })}
49        </div>
50    }
51}