Skip to main content

yggdrasil/api/posts/
mermaid_preview.rs

1//! 后台编辑器的 Mermaid 预览:与文章保存时同一套服务端渲染。
2
3use crate::api::error::ApiError;
4use leptos::prelude::*;
5
6#[cfg(feature = "server")]
7use super::helpers::get_current_admin_user;
8#[cfg(feature = "server")]
9use crate::api::error::AppError;
10
11/// 预览源码长度上限(字节)。
12#[cfg(feature = "server")]
13const MAX_SOURCE_LEN: usize = 20_000;
14
15/// 渲染一张图,返回浅色、深色两份 SVG 的 HTML(`mermaid-light` / `mermaid-dark` 两个 div)。
16#[server(RenderMermaidPreview, endpoint = "render_mermaid_preview", input = leptos::server_fn::codec::Json)]
17pub async fn render_mermaid_preview(source: String) -> Result<String, ApiError> {
18    let _user = get_current_admin_user().await?;
19    #[cfg(feature = "server")]
20    {
21        if source.len() > MAX_SOURCE_LEN {
22            return Err(AppError::BadRequest("图表源码过长".into()).into());
23        }
24        let rendered = tokio::task::spawn_blocking(move || {
25            crate::api::markdown::mermaid::render_diagram(&source, 0)
26        })
27        .await
28        .map_err(|_| AppError::Internal("图表渲染任务失败"))?;
29        rendered.map_err(|e| AppError::BadRequest(e).into())
30    }
31    #[cfg(not(feature = "server"))]
32    {
33        Ok(String::new())
34    }
35}