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}