Skip to main content

yggdrasil/components/post/
post_nav_links.rs

1//! 文章上一篇/下一篇导航组件
2//!
3//! 在文章详情页底部提供相邻文章的快速跳转。
4
5use dioxus::prelude::*;
6use dioxus::router::components::Link;
7
8use crate::models::post::PostNav;
9use crate::router::Route;
10
11/// 文章相邻导航组件。
12///
13/// Props:
14/// - `prev`:上一篇文章摘要
15/// - `next`:下一篇文章摘要
16/// - `full_reload`:链接走整页加载而非客户端路由(默认 false)。仅当本组件
17///   渲染在 admin 布局内(如 `/admin/preview`)时传 true:跨 layout 分支的
18///   客户端导航会触发 dioxus 0.7.10 的 suspense 卸载双重回收 bug(详见
19///   `src/pages/admin/preview.rs` 模块文档),整页加载可完全规避。
20///
21/// 左右两侧分别渲染 Prev/Next 链接,若无相邻文章则占位空白。
22#[component]
23pub fn PostNavLinks(
24    prev: Option<PostNav>,
25    next: Option<PostNav>,
26    #[props(default = false)] full_reload: bool,
27) -> Element {
28    // NavigationTarget::External 生成原生 <a href>(Link 不接管 preventDefault),
29    // 浏览器整页加载;内部路由变体保持客户端导航。
30    let prev_to = prev.as_ref().map(|p| {
31        super::nav_target(
32            Route::PostDetail {
33                slug: p.slug.clone(),
34            },
35            full_reload,
36        )
37    });
38    let next_to = next.as_ref().map(|p| {
39        super::nav_target(
40            Route::PostDetail {
41                slug: p.slug.clone(),
42            },
43            full_reload,
44        )
45    });
46    rsx! {
47        nav { class: "paginav",
48            if let (Some(prev_post), Some(prev_to)) = (prev, prev_to) {
49                Link {
50                    class: "prev",
51                    to: prev_to,
52                    span { class: "title", "« Prev" }
53                    span { class: "post-title-nav", "{prev_post.title}" }
54                }
55            } else {
56                span { class: "prev" }
57            }
58
59            if let (Some(next_post), Some(next_to)) = (next, next_to) {
60                Link {
61                    class: "next",
62                    to: next_to,
63                    span { class: "title", "Next »" }
64                    span { class: "post-title-nav", "{next_post.title}" }
65                }
66            } else {
67                span { class: "next" }
68            }
69        }
70    }
71}