Skip to main content

yggdrasil/pages/
about.rs

1//! 关于页面模块。
2//!
3//! 对应路由 `/about`。
4//!
5//! 该页面为静态展示页面,不发起任何 server function 调用。
6//! 页面刻意不做常规的站点简介 / 技术栈 / 联系方式罗列,而是围绕一个呼应展开:
7//! 「世界……遗忘我……」是大慈树王把自己从世界树(Irminsul)中抹除时的请求,
8//! 而本站名为 Yggdrasil——北欧神话中的世界树,记忆的容器。
9//! 书写即对遗忘的抵抗:世界遗忘的,树记得。
10//!
11//! 文末的「年轮」小节收录站点元信息:站内条目(更新日志)用 `Link` 走 SPA
12//! 导航,站外/静态条目(如 rustdoc 站点文档)向 [`LINKS`] 数组追加一行即可。
13
14use dioxus::prelude::*;
15
16use crate::router::Route;
17
18/// 「年轮」外链列表:`(URL, 名称, 一句描述)`。
19///
20/// 仅收录 Dioxus SPA 路由之外的目标(静态文件或站外地址),
21/// 因此渲染为普通 `<a target="_blank">` 而非 `Link`——
22/// `Link` 只接受 `Route` 枚举,指向未注册路径会被路由兜进 404。
23/// 站内条目(如更新日志)不使用本数组,直接在下方以 `Link` 单独渲染。
24const LINKS: &[(&str, &str, &str)] = &[(
25    "/doc/yggdrasil/index.html",
26    "站点文档",
27    "这棵树是如何长成的",
28)];
29
30/// 关于页面组件,对应路由 `/about`。
31///
32/// 静态三段式结构:引言区(引文 + 落款 + 分隔线)→ 短文 → 「年轮」链接列表。
33/// 全部内容编译期确定,无 signal、无副作用。
34#[component]
35pub fn About() -> Element {
36    rsx! {
37        div { class: "animate-page-enter",
38            header { class: "page-header mb-6",
39                h1 { class: "text-4xl font-bold text-paper-primary tracking-tight",
40                    "关于"
41                }
42            }
43
44            // 引言区:引文即页面的视觉锚点,仪式感与 404 页保持一致
45            div { class: "text-center py-12 md:py-16",
46                blockquote { class: "text-2xl md:text-4xl font-medium text-paper-primary leading-relaxed tracking-wide",
47                    "世界……遗忘我……"
48                }
49                p { class: "mt-6 text-sm text-paper-tertiary", "—— 大慈树王" }
50                div { class: "w-12 h-px bg-paper-border mx-auto mt-10" }
51            }
52
53            // 短文:对引文的回应,「树记得」落回站名
54            div { class: "max-w-xl mx-auto text-center space-y-4 text-paper-secondary leading-loose",
55                p {
56                    "Yggdrasil,北欧神话中的世界树。根须贯穿九界,枝叶承载记忆。"
57                }
58                p {
59                    "人会遗忘,也终将被遗忘——而写下的不会。"
60                    span { class: "text-paper-primary", "世界遗忘的,树记得。" }
61                }
62            }
63
64            // 年轮:站点元链接。行样式镜像归档页的安静感(发丝线 + 排版层级),
65            // hover 时名称转为全站唯一强调色,箭头轻移作为确认。
66            div { class: "mt-16 md:mt-20",
67                p { class: "text-center text-sm font-medium tracking-[0.2em] text-paper-tertiary mb-2",
68                    "年轮"
69                }
70                div { class: "max-w-xl mx-auto",
71                    // 站内条目:SPA 导航用 Link,右箭头 →;外链行是新标签页 ↗。
72                    // 更新日志是固定设施,不进 LINKS 数组。
73                    Link {
74                        to: Route::Changelog {},
75                        class: "group flex items-baseline justify-between gap-4 py-3 border-b border-paper-border/50",
76                        span { class: "flex items-baseline gap-1.5 text-paper-primary font-medium group-hover:text-paper-accent transition-colors",
77                            "更新日志"
78                            svg {
79                                xmlns: "http://www.w3.org/2000/svg",
80                                width: "14",
81                                height: "14",
82                                view_box: "0 0 24 24",
83                                fill: "none",
84                                stroke: "currentColor",
85                                stroke_width: "2",
86                                stroke_linecap: "round",
87                                stroke_linejoin: "round",
88                                class: "text-paper-tertiary group-hover:text-paper-accent group-hover:translate-x-0.5 transition-all",
89                                path { d: "M5 12h14M13 6l6 6-6 6" }
90                            }
91                        }
92                        span { class: "text-sm text-paper-secondary",
93                            "每一圈年轮,都是一次生长"
94                        }
95                    }
96                    for (href, name, desc) in LINKS.iter().copied() {
97                        a {
98                            key: "{href}",
99                            href,
100                            target: "_blank",
101                            rel: "noopener noreferrer",
102                            class: "group flex items-baseline justify-between gap-4 py-3 border-b border-paper-border/50",
103                            span { class: "flex items-baseline gap-1.5 text-paper-primary font-medium group-hover:text-paper-accent transition-colors",
104                                "{name}"
105                                svg {
106                                    xmlns: "http://www.w3.org/2000/svg",
107                                    width: "14",
108                                    height: "14",
109                                    view_box: "0 0 24 24",
110                                    fill: "none",
111                                    stroke: "currentColor",
112                                    stroke_width: "2",
113                                    stroke_linecap: "round",
114                                    stroke_linejoin: "round",
115                                    class: "text-paper-tertiary group-hover:text-paper-accent group-hover:-translate-y-0.5 group-hover:translate-x-0.5 transition-all",
116                                    path { d: "M7 17L17 7M7 7h10v10" }
117                                }
118                            }
119                            span { class: "text-sm text-paper-secondary", "{desc}" }
120                        }
121                    }
122                }
123            }
124        }
125    }
126}