//! 前台布局组件 //! //! 包裹所有前台路由,提供统一的 Header、Footer 与主内容区容器, //! 并为不同路由在 SuspenseBoundary 中展示对应的骨架屏。 use dioxus::prelude::*; use crate::components::footer::Footer; use crate::components::header::Header; use crate::components::nav::use_nav_items; use crate::components::skeletons::archive_skeleton::ArchiveSkeleton; use crate::components::skeletons::delayed_skeleton::DelayedSkeleton; use crate::components::skeletons::home_skeleton::HomeSkeleton; use crate::components::skeletons::post_detail_skeleton::PostDetailSkeleton; use crate::components::skeletons::search_skeleton::SearchSkeleton; use crate::components::skeletons::tags_skeleton::TagsSkeleton; use crate::router::Route; use crate::theme::ThemeToggle; /// 根据当前前台路由选择对应的骨架屏组件。 fn route_skeleton(route: &Route) -> Element { match route { Route::Archives {} => rsx! { DelayedSkeleton { ArchiveSkeleton {} } }, Route::Tags {} | Route::TagDetail { .. } => rsx! { DelayedSkeleton { TagsSkeleton {} } }, Route::Search {} => rsx! { DelayedSkeleton { SearchSkeleton {} } }, Route::PostDetail { .. } => rsx! { DelayedSkeleton { PostDetailSkeleton {} } }, Route::NotFound { .. } => rsx! { div { class: "py-20 md:py-28" } }, _ => rsx! { DelayedSkeleton { HomeSkeleton {} } }, } } /// 前台整体布局组件。 /// /// 负责渲染 Header(含前台导航与主题切换)、主内容区与 Footer, /// 并在路由内容加载过程中显示与路由匹配的骨架屏。 #[component] pub fn FrontendLayout() -> Element { let route = use_route::(); let nav_items = use_nav_items(route.clone()); rsx! { div { class: "min-h-screen flex flex-col bg-paper-theme", Header { nav_items, right_content: rsx! { ThemeToggle {} }, } main { class: "flex-1 w-full max-w-3xl mx-auto px-6 py-6", SuspenseBoundary { fallback: move |_| route_skeleton(&route), Outlet:: {} } } Footer {} } } }