- 将 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>
72 lines
3.0 KiB
Rust
72 lines
3.0 KiB
Rust
use dioxus::prelude::*;
|
|
|
|
use crate::components::admin_layout::AdminLayout;
|
|
|
|
fn markdown_to_html(input: &str) -> String {
|
|
let parser = pulldown_cmark::Parser::new(input);
|
|
let mut html = String::new();
|
|
pulldown_cmark::html::push_html(&mut html, parser);
|
|
html
|
|
}
|
|
|
|
#[component]
|
|
pub fn WritePage() -> Element {
|
|
let mut title = use_signal(|| "".to_string());
|
|
let mut content = use_signal(|| "".to_string());
|
|
let preview_html = use_memo(move || {
|
|
markdown_to_html(&content())
|
|
});
|
|
|
|
rsx! {
|
|
AdminLayout {
|
|
div { class: "space-y-4",
|
|
// 标题输入
|
|
input {
|
|
class: "w-full text-2xl font-bold bg-transparent border-b border-gray-200 dark:border-[#333] py-2 mb-4 text-gray-900 dark:text-[#dadadb] placeholder-gray-400 dark:placeholder-[#9b9c9d] focus:outline-none",
|
|
placeholder: "文章标题...",
|
|
value: "{title}",
|
|
oninput: move |evt| title.set(evt.value()),
|
|
}
|
|
|
|
// 两栏布局
|
|
div { class: "grid grid-cols-1 md:grid-cols-2 gap-6",
|
|
// 编辑区
|
|
div { class: "space-y-2",
|
|
label { class: "text-sm text-gray-500 dark:text-[#9b9c9d]",
|
|
"Markdown"
|
|
}
|
|
textarea {
|
|
class: "w-full h-[500px] bg-gray-50 dark:bg-[#2e2e33] rounded-lg p-4 font-mono text-sm text-gray-800 dark:text-[#dadadb] placeholder-gray-400 dark:placeholder-[#9b9c9d] border border-gray-200 dark:border-[#333] focus:outline-none focus:border-gray-400 dark:focus:border-gray-600 resize-none",
|
|
placeholder: "在此输入 Markdown...",
|
|
value: "{content}",
|
|
oninput: move |evt| content.set(evt.value()),
|
|
}
|
|
}
|
|
|
|
// 预览区
|
|
div { class: "space-y-2",
|
|
label { class: "text-sm text-gray-500 dark:text-[#9b9c9d]",
|
|
"预览"
|
|
}
|
|
div {
|
|
class: "w-full h-[500px] overflow-y-auto bg-white dark:bg-[#2e2e33] rounded-lg p-4 border border-gray-200 dark:border-[#333] prose dark:prose-invert max-w-none",
|
|
dangerous_inner_html: "{preview_html}",
|
|
}
|
|
}
|
|
}
|
|
|
|
// 保存按钮
|
|
button {
|
|
class: "mt-4 px-6 py-2 bg-gray-900 dark:bg-[#dadadb] text-white dark:text-gray-900 rounded-full font-medium hover:opacity-80 transition-opacity",
|
|
onclick: move |_| {
|
|
let t = title();
|
|
let c = content();
|
|
println!("保存文章: title={}, content_len={}", t, c.len());
|
|
},
|
|
"保存草稿"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|