contributor_graphs/
html.rs1use crate::model::{Contributor, RepoMeta};
2use crate::theme::Theme;
3
4const TEMPLATE: &str = include_str!("assets/template.html");
5
6pub struct HtmlOptions {
7 pub accent: String,
8 pub by_affiliation: bool,
9 pub unaffiliated_label: String,
10 pub custom_themes: Vec<Theme>,
12 pub theme_order: Vec<String>,
14 pub default_theme: Option<String>,
17 pub lock_theme: bool,
19}
20
21impl Default for HtmlOptions {
22 fn default() -> Self {
23 HtmlOptions {
24 accent: "#2f6feb".into(),
25 by_affiliation: false,
26 unaffiliated_label: "Unaffiliated".into(),
27 custom_themes: Vec::new(),
28 theme_order: vec!["light".into(), "dark".into(), "wikipedia".into()],
29 default_theme: None,
30 lock_theme: false,
31 }
32 }
33}
34
35pub fn render_html(meta: &RepoMeta, contributors: &[Contributor], opts: &HtmlOptions) -> String {
36 let custom: Vec<serde_json::Value> = opts.custom_themes.iter().map(Theme::to_json).collect();
37 let data = serde_json::json!({
38 "repo": meta,
39 "contributors": contributors,
40 "accent": opts.accent,
41 "byAffiliation": opts.by_affiliation,
42 "unaffiliated": opts.unaffiliated_label,
43 "themes": custom,
44 "themeOrder": opts.theme_order,
45 "defaultTheme": opts.default_theme,
46 "lockTheme": opts.lock_theme,
47 });
48 let json = serde_json::to_string(&data)
50 .expect("serialize data")
51 .replace("</", "<\\/");
52 let title = format!("{} ยท contributors", meta.name);
53 TEMPLATE
54 .replace("__PAGE_TITLE__", &html_escape(&title))
55 .replace("__DATA__", &json)
56}
57
58fn html_escape(s: &str) -> String {
59 s.replace('&', "&")
60 .replace('<', "<")
61 .replace('>', ">")
62}