rainbeam_shared/
ui.rs

1use ammonia::Builder;
2use markdown::{to_html_with_options, Options, CompileOptions, ParseOptions, Constructs};
3use std::collections::HashSet;
4
5/// Render markdown input into HTML
6pub fn render_markdown(input: &str) -> String {
7    let options = Options {
8        compile: CompileOptions {
9            allow_any_img_src: false,
10            allow_dangerous_html: true,
11            gfm_task_list_item_checkable: false,
12            gfm_tagfilter: false,
13            ..Default::default()
14        },
15        parse: ParseOptions {
16            constructs: Constructs {
17                gfm_autolink_literal: true,
18                ..Default::default()
19            },
20            gfm_strikethrough_single_tilde: false,
21            math_text_single_dollar: false,
22            mdx_expression_parse: None,
23            mdx_esm_parse: None,
24            ..Default::default()
25        },
26    };
27
28    let html = match to_html_with_options(input, &options) {
29        Ok(h) => h,
30        Err(e) => e.to_string(),
31    };
32
33    let mut allowed_attributes = HashSet::new();
34    allowed_attributes.insert("id");
35    allowed_attributes.insert("class");
36    allowed_attributes.insert("ref");
37    allowed_attributes.insert("aria-label");
38    allowed_attributes.insert("lang");
39    allowed_attributes.insert("title");
40    allowed_attributes.insert("align");
41    allowed_attributes.insert("src");
42
43    Builder::default()
44        .generic_attributes(allowed_attributes)
45        .add_tags(&[
46            "video", "source", "img", "b", "span", "p", "i", "strong", "em", "a",
47        ])
48        .rm_tags(&["script", "style", "link", "canvas"])
49        .add_tag_attributes("a", &["href", "target"])
50        .clean(&html)
51        .to_string()
52        .replace(
53            "src=\"",
54            "loading=\"lazy\" src=\"/api/v0/util/ext/image?img=",
55        )
56        .replace("<video loading=", "<video controls loading=")
57        .replace("--&gt;", "<align class=\"right\">")
58        .replace("-&gt;", "<align class=\"center\">")
59        .replace("&lt;-", "</align>")
60}