fix(ui): apply mount animation inside each page component to avoid skeleton interception
This commit is contained in:
parent
d361bca220
commit
46860f7c41
@ -60,11 +60,7 @@ pub fn FrontendLayout() -> Element {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
main { class: "flex-1 w-full max-w-4xl mx-auto px-6 py-6 md:py-12 overflow-hidden",
|
main { class: "flex-1 w-full max-w-4xl mx-auto px-6 py-6 md:py-12 overflow-hidden",
|
||||||
div {
|
SuspenseBoundary { fallback: move |_| route_skeleton(&route), Outlet::<Route> {} }
|
||||||
key: "{route}",
|
|
||||||
class: "animate-page-enter",
|
|
||||||
SuspenseBoundary { fallback: move |_| route_skeleton(&route), Outlet::<Route> {} }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Footer {}
|
Footer {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,11 +13,13 @@ use dioxus::prelude::*;
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn About() -> Element {
|
pub fn About() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
header { class: "page-header mb-6",
|
div { class: "animate-page-enter",
|
||||||
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "关于" }
|
header { class: "page-header mb-6",
|
||||||
}
|
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "关于" }
|
||||||
article { class: "prose dark:prose-invert max-w-none text-paper-content leading-relaxed",
|
}
|
||||||
p { "世界……遗忘我……" }
|
article { class: "prose dark:prose-invert max-w-none text-paper-content leading-relaxed",
|
||||||
|
p { "世界……遗忘我……" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,10 +101,12 @@ fn group_posts(posts: &[PostListItem]) -> Vec<YearGroup> {
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn Archives() -> Element {
|
pub fn Archives() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
header { class: "page-header mb-6",
|
div { class: "animate-page-enter",
|
||||||
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "归档" }
|
header { class: "page-header mb-6",
|
||||||
|
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "归档" }
|
||||||
|
}
|
||||||
|
ArchivesContent {}
|
||||||
}
|
}
|
||||||
ArchivesContent {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,8 +40,10 @@ pub fn HomePage(page: i32) -> Element {
|
|||||||
let current_page = page.max(1);
|
let current_page = page.max(1);
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
HomeInfo {}
|
div { class: "animate-page-enter",
|
||||||
HomePosts { current_page }
|
HomeInfo {}
|
||||||
|
HomePosts { current_page }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ pub fn PostDetail(slug: String) -> Element {
|
|||||||
match post_data {
|
match post_data {
|
||||||
Some(Ok(post)) => {
|
Some(Ok(post)) => {
|
||||||
rsx! {
|
rsx! {
|
||||||
article { class: "post-single", key: "{post.slug}",
|
article { class: "post-single animate-page-enter", key: "{post.slug}",
|
||||||
PostHeader { post: post.clone() }
|
PostHeader { post: post.clone() }
|
||||||
|
|
||||||
// 如果文章设置了封面图,则渲染封面组件。
|
// 如果文章设置了封面图,则渲染封面组件。
|
||||||
|
|||||||
@ -44,53 +44,55 @@ pub fn Search() -> Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
header { class: "page-header mb-6",
|
div { class: "animate-page-enter",
|
||||||
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "搜索" }
|
header { class: "page-header mb-6",
|
||||||
}
|
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "搜索" }
|
||||||
div { class: "mb-8",
|
}
|
||||||
div { class: "flex gap-2",
|
div { class: "mb-8",
|
||||||
input {
|
div { class: "flex gap-2",
|
||||||
class: "flex-1 px-4 py-2 border border-paper-border rounded-lg bg-paper-entry text-paper-primary placeholder:text-paper-tertiary focus:outline-none focus:border-paper-accent focus:ring-1 focus:ring-paper-accent/30",
|
input {
|
||||||
r#type: "text",
|
class: "flex-1 px-4 py-2 border border-paper-border rounded-lg bg-paper-entry text-paper-primary placeholder:text-paper-tertiary focus:outline-none focus:border-paper-accent focus:ring-1 focus:ring-paper-accent/30",
|
||||||
placeholder: "输入关键词搜索文章...",
|
r#type: "text",
|
||||||
value: query(),
|
placeholder: "输入关键词搜索文章...",
|
||||||
oninput: move |e| query.set(e.value()),
|
value: query(),
|
||||||
onkeydown: move |e| {
|
oninput: move |e| query.set(e.value()),
|
||||||
if e.key() == Key::Enter {
|
onkeydown: move |e| {
|
||||||
on_search()
|
if e.key() == Key::Enter {
|
||||||
}
|
on_search()
|
||||||
},
|
}
|
||||||
}
|
},
|
||||||
button {
|
}
|
||||||
class: "px-6 py-2 bg-paper-accent text-white rounded-full font-medium hover:brightness-110 active:scale-[0.98] transition-all duration-200",
|
button {
|
||||||
onclick: move |_| on_search(),
|
class: "px-6 py-2 bg-paper-accent text-white rounded-full font-medium hover:brightness-110 active:scale-[0.98] transition-all duration-200",
|
||||||
"搜索"
|
onclick: move |_| on_search(),
|
||||||
|
"搜索"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// 根据搜索状态展示骨架屏、结果列表、空状态或错误提示。
|
||||||
// 根据搜索状态展示骨架屏、结果列表、空状态或错误提示。
|
if is_searching() {
|
||||||
if is_searching() {
|
DelayedSkeleton { SearchSkeleton {} }
|
||||||
DelayedSkeleton { SearchSkeleton {} }
|
} else if let Some(Ok(PostListResponse { posts, total: _ })) = search_res() {
|
||||||
} else if let Some(Ok(PostListResponse { posts, total: _ })) = search_res() {
|
if posts.is_empty() {
|
||||||
if posts.is_empty() {
|
EmptyState {
|
||||||
EmptyState {
|
title: "未找到相关文章",
|
||||||
title: "未找到相关文章",
|
description: "换个关键词再试一次吧",
|
||||||
description: "换个关键词再试一次吧",
|
}
|
||||||
|
} else {
|
||||||
|
for post in posts.iter() {
|
||||||
|
PostCard { key: "{post.id}", post: post.clone() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if search_res().as_ref().map(|r| r.is_err()).unwrap_or(false) {
|
||||||
|
div { class: "text-center text-red-500 dark:text-red-400 py-20", "搜索失败" }
|
||||||
} else {
|
} else {
|
||||||
for post in posts.iter() {
|
div { class: "flex flex-col items-center justify-center mt-24 mb-12",
|
||||||
PostCard { key: "{post.id}", post: post.clone() }
|
img {
|
||||||
}
|
class: "w-56 h-auto rounded-lg select-none dark:brightness-90",
|
||||||
}
|
src: "/images/xiantiaoxiaogou_02.webp",
|
||||||
} else if search_res().as_ref().map(|r| r.is_err()).unwrap_or(false) {
|
alt: "空状态提示",
|
||||||
div { class: "text-center text-red-500 dark:text-red-400 py-20", "搜索失败" }
|
draggable: "false",
|
||||||
} else {
|
}
|
||||||
div { class: "flex flex-col items-center justify-center mt-24 mb-12 page-enter",
|
|
||||||
img {
|
|
||||||
class: "w-56 h-auto rounded-lg select-none dark:brightness-90",
|
|
||||||
src: "/images/xiantiaoxiaogou_02.webp",
|
|
||||||
alt: "空状态提示",
|
|
||||||
draggable: "false",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,10 +27,12 @@ use crate::router::Route;
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn Tags() -> Element {
|
pub fn Tags() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
header { class: "page-header mb-6",
|
div { class: "animate-page-enter",
|
||||||
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "标签" }
|
header { class: "page-header mb-6",
|
||||||
|
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "标签" }
|
||||||
|
}
|
||||||
|
TagsContent {}
|
||||||
}
|
}
|
||||||
TagsContent {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,10 +107,12 @@ fn TagsContent() -> Element {
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn TagDetail(tag: String) -> Element {
|
pub fn TagDetail(tag: String) -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
header { class: "page-header mb-6",
|
div { class: "animate-page-enter",
|
||||||
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "{tag}" }
|
header { class: "page-header mb-6",
|
||||||
|
h1 { class: "text-4xl font-bold text-paper-primary tracking-tight", "{tag}" }
|
||||||
|
}
|
||||||
|
TagDetailContent { tag: tag.clone() }
|
||||||
}
|
}
|
||||||
TagDetailContent { tag: tag.clone() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user