diff --git a/src/components/skeletons/archive_skeleton.rs b/src/components/skeletons/archive_skeleton.rs index d570b2d..7f20862 100644 --- a/src/components/skeletons/archive_skeleton.rs +++ b/src/components/skeletons/archive_skeleton.rs @@ -1,4 +1,5 @@ use dioxus::prelude::*; +use crate::components::skeletons::atoms::*; /// 归档页骨架屏 /// 结构:统计行("共 N 篇文章") + 年份标题 + 月份标题 + 文章条目列表 @@ -9,29 +10,29 @@ pub fn ArchiveSkeleton() -> Element { div { // 统计行占位 div { class: "mt-2 mb-6", - div { class: "h-5 w-32 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-5 w-32".to_string() } } // 年份分组占位 for _ in 0..2 { div { class: "archive-year mt-10", // 年份标题 (h2 text-2xl) - div { class: "h-8 w-24 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-4" } + SkeletonBox { class: "h-8 w-24 mb-4".to_string() } // 月份分组 for _ in 0..2 { div { class: "archive-month flex flex-col md:flex-row md:items-start py-2.5 border-b border-gray-100 dark:border-[#333]/50", // 月份标题 (h3 text-lg, md:w-[200px]) - div { class: "h-6 w-32 md:w-[200px] shrink-0 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-2 md:mb-0 md:py-1.5" } + SkeletonBox { class: "h-6 w-32 md:w-[200px] shrink-0 mb-2 md:mb-0 md:py-1.5".to_string() } // 文章条目列表 div { class: "flex-1 space-y-3", for _ in 0..3 { div { class: "archive-entry py-1.5 my-2.5", // 文章标题 - div { class: "h-4 w-3/4 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-1" } + SkeletonBox { class: "h-4 w-3/4 mb-1".to_string() } // 日期 - div { class: "h-3 w-20 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-3 w-20".to_string() } } } } diff --git a/src/components/skeletons/atoms.rs b/src/components/skeletons/atoms.rs new file mode 100644 index 0000000..ae3a88d --- /dev/null +++ b/src/components/skeletons/atoms.rs @@ -0,0 +1,30 @@ +use dioxus::prelude::*; + +#[component] +pub fn SkeletonLine(width: String, height: String) -> Element { + rsx! { + div { + class: "bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse", + style: "width: {width}; height: {height};", + } + } +} + +#[component] +pub fn SkeletonBox(class: String) -> Element { + rsx! { + div { + class: "bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse {class}", + } + } +} + +#[component] +pub fn SkeletonCard() -> Element { + rsx! { + div { class: "rounded-xl bg-white dark:bg-[#2e2e33] border border-gray-200 dark:border-[#333] p-6 text-center space-y-3", + SkeletonLine { width: "64px".to_string(), height: "36px".to_string() } + SkeletonLine { width: "80px".to_string(), height: "16px".to_string() } + } + } +} diff --git a/src/components/skeletons/mod.rs b/src/components/skeletons/mod.rs index 453fc1f..031f247 100644 --- a/src/components/skeletons/mod.rs +++ b/src/components/skeletons/mod.rs @@ -1,3 +1,4 @@ +pub mod atoms; pub mod archive_skeleton; pub mod delayed_skeleton; pub mod home_skeleton; diff --git a/src/components/skeletons/post_detail_skeleton.rs b/src/components/skeletons/post_detail_skeleton.rs index 0033acc..b0339ea 100644 --- a/src/components/skeletons/post_detail_skeleton.rs +++ b/src/components/skeletons/post_detail_skeleton.rs @@ -1,4 +1,5 @@ use dioxus::prelude::*; +use crate::components::skeletons::atoms::*; /// 文章详情页骨架屏 /// 结构:面包屑 + 标题(h1) + 摘要 + 元信息 + 封面图 + 正文(多段) + Footer @@ -7,48 +8,48 @@ pub fn PostDetailSkeleton() -> Element { rsx! { article { class: "post-single", // 面包屑占位 - div { class: "h-4 w-48 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-6" } + SkeletonBox { class: "h-4 w-48 mb-6".to_string() } // 标题占位 (模拟 h1) - div { class: "h-10 w-4/5 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-4" } + SkeletonBox { class: "h-10 w-4/5 mb-4".to_string() } // 摘要占位 - div { class: "h-5 w-2/3 bg-gray-200 dark:bg-[#2a2a2a] rounded mb-4" } + SkeletonBox { class: "h-5 w-2/3 mb-4".to_string() } // 元信息行 (作者 · 日期 · 阅读时间) div { class: "flex items-center gap-2 mb-8", - div { class: "h-4 w-16 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-1 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-24 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-1 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-20 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-4 w-16".to_string() } + SkeletonBox { class: "h-4 w-1".to_string() } + SkeletonBox { class: "h-4 w-24".to_string() } + SkeletonBox { class: "h-4 w-1".to_string() } + SkeletonBox { class: "h-4 w-20".to_string() } } // 封面图占位 (模拟 PostCover 16:9 比例) - div { class: "w-full aspect-video bg-gray-200 dark:bg-[#2a2a2a] rounded-lg mb-8" } + SkeletonBox { class: "w-full aspect-video rounded-lg mb-8".to_string() } // 正文段落占位 (模拟多段 PostContent) div { class: "space-y-4 mb-8", - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-5/6 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-3/4 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-5/6".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-3/4".to_string() } // 空行模拟段落间距 div { class: "h-2" } - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-full bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-2/3 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-2/3".to_string() } } // PostFooter 占位 div { class: "border-t border-gray-200 dark:border-[#333] pt-6 mt-8", div { class: "flex items-center justify-between", - div { class: "h-4 w-32 bg-gray-200 dark:bg-[#2a2a2a] rounded" } - div { class: "h-4 w-24 bg-gray-200 dark:bg-[#2a2a2a] rounded" } + SkeletonBox { class: "h-4 w-32".to_string() } + SkeletonBox { class: "h-4 w-24".to_string() } } } } } -} \ No newline at end of file +} diff --git a/src/components/write_skeleton.rs b/src/components/write_skeleton.rs index de2af60..4026f2c 100644 --- a/src/components/write_skeleton.rs +++ b/src/components/write_skeleton.rs @@ -1,11 +1,12 @@ use dioxus::prelude::*; +use crate::components::skeletons::atoms::*; #[component] pub fn WriteSkeleton() -> Element { rsx! { div { class: "space-y-4", // 标题输入骨架 - div { class: "w-full h-[52px] bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse mb-4" } + SkeletonBox { class: "w-full h-[52px] mb-4".to_string() } // 编辑器区域骨架 div { @@ -13,28 +14,28 @@ pub fn WriteSkeleton() -> Element { // 工具栏骨架 div { class: "flex gap-2 pb-4 border-b border-gray-100 dark:border-[#333]", for _ in 0..8 { - div { class: "w-8 h-8 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse" } + SkeletonBox { class: "w-8 h-8".to_string() } } } // 内容行骨架 div { class: "space-y-3 pt-2", - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[90%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-full" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[85%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[95%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[60%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-full" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[75%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[80%]" } + SkeletonBox { class: "h-4 w-[90%]".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-[85%]".to_string() } + SkeletonBox { class: "h-4 w-[95%]".to_string() } + SkeletonBox { class: "h-4 w-[60%]".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-[75%]".to_string() } + SkeletonBox { class: "h-4 w-[80%]".to_string() } div { class: "h-4" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[70%]" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-full" } - div { class: "h-4 bg-gray-200 dark:bg-[#2a2a2a] rounded animate-pulse w-[90%]" } + SkeletonBox { class: "h-4 w-[70%]".to_string() } + SkeletonBox { class: "h-4 w-full".to_string() } + SkeletonBox { class: "h-4 w-[90%]".to_string() } } } // 保存按钮骨架 - div { class: "mt-4 h-10 w-28 bg-gray-200 dark:bg-[#2a2a2a] rounded-full animate-pulse" } + SkeletonBox { class: "mt-4 h-10 w-28 rounded-full".to_string() } } } }