- 将 monolithic admin.rs 拆分为 admin/ 目录模块(dashboard、write) - 新增 components 模块:Header、Footer、AdminLayout - 新增 /admin/write 文章撰写页面,支持 Markdown 实时预览 - 添加 pulldown-cmark 依赖用于 Markdown 渲染 - .env 移出版本控制,新增 .env.example 模板 - Home、Archives、Tags、Login、Register 等页面适配新组件 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
93 lines
2.9 KiB
Rust
93 lines
2.9 KiB
Rust
use dioxus::prelude::*;
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
use wasm_bindgen::JsCast;
|
|
|
|
use crate::api::auth::{get_current_user, logout};
|
|
use crate::components::header::{Header, NavItemConfig};
|
|
use crate::components::footer::Footer;
|
|
use crate::router::Route;
|
|
|
|
#[component]
|
|
pub fn AdminLayout(children: Element) -> Element {
|
|
let user_resource =
|
|
use_resource(|| async move { get_current_user().await.ok().and_then(|r| r.user) });
|
|
|
|
let navigator = dioxus::router::navigator();
|
|
let route = use_route::<Route>();
|
|
|
|
let admin_nav_items = vec![
|
|
NavItemConfig {
|
|
href: "/admin",
|
|
label: "仪表盘",
|
|
is_active: matches!(route, Route::AdminPage {}),
|
|
},
|
|
NavItemConfig {
|
|
href: "/admin/write",
|
|
label: "写文章",
|
|
is_active: matches!(route, Route::WritePage {}),
|
|
},
|
|
NavItemConfig {
|
|
href: "/",
|
|
label: "前台",
|
|
is_active: false,
|
|
},
|
|
];
|
|
|
|
let nav = navigator;
|
|
let logout_button = rsx! {
|
|
button {
|
|
class: "text-sm text-gray-600 dark:text-[#9b9c9d] hover:text-gray-900 dark:hover:text-[#dadadb] transition-colors",
|
|
onclick: move |_| {
|
|
let nav = nav;
|
|
spawn(async move {
|
|
let _ = logout().await;
|
|
#[cfg(target_arch = "wasm32")]
|
|
{
|
|
let cookie = "session=; path=/; max-age=0";
|
|
if let Some(window) = web_sys::window() {
|
|
if let Some(document) = window.document() {
|
|
let _ = document.dyn_into::<web_sys::HtmlDocument>()
|
|
.map(|d| d.set_cookie(cookie));
|
|
}
|
|
}
|
|
}
|
|
let _ = nav.push("/login");
|
|
});
|
|
},
|
|
"登出"
|
|
}
|
|
};
|
|
|
|
let user_data = user_resource.read().clone();
|
|
|
|
let should_redirect = matches!(user_data.as_ref(), Some(None));
|
|
|
|
use_effect(move || {
|
|
if should_redirect {
|
|
navigator.push("/login");
|
|
}
|
|
});
|
|
|
|
match user_data.as_ref() {
|
|
Some(Some(_user)) => {
|
|
rsx! {
|
|
div { class: "min-h-screen flex flex-col bg-white dark:bg-[#1d1e20]",
|
|
Header { nav_items: admin_nav_items, right_content: logout_button }
|
|
main { class: "flex-1 w-full max-w-5xl mx-auto px-6 py-8",
|
|
{children}
|
|
}
|
|
Footer {}
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
rsx! {
|
|
div { class: "min-h-screen flex items-center justify-center bg-white dark:bg-[#1d1e20]",
|
|
p { class: "text-gray-600 dark:text-[#9b9c9d]", "加载中..." }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|