127 lines
3.1 KiB
Rust
127 lines
3.1 KiB
Rust
use axum::{
|
|
http::{HeaderValue, header},
|
|
response::{Html, IntoResponse, Response},
|
|
};
|
|
|
|
const MODULES: &[&str] = &[
|
|
"api",
|
|
"authorship",
|
|
"auth-ui",
|
|
"clipboard",
|
|
"editor-format",
|
|
"emoji-data",
|
|
"emoji-picker",
|
|
"image-upload",
|
|
"logger",
|
|
"markdown",
|
|
"modal",
|
|
"note-api",
|
|
"note-editor",
|
|
"note-files",
|
|
"session",
|
|
"socket",
|
|
"toast",
|
|
"url-state",
|
|
"security",
|
|
];
|
|
|
|
pub fn render_html(
|
|
template: &str,
|
|
asset_version: &str,
|
|
registration_enabled: bool,
|
|
external_auth: bool,
|
|
frontend_log_level: &str,
|
|
upload_max_size_bytes: usize,
|
|
entrypoint: &str,
|
|
) -> Response {
|
|
let urls = AssetUrls::new(asset_version);
|
|
let frontend_config = frontend_config(frontend_log_level, upload_max_size_bytes, external_auth);
|
|
let html = template
|
|
.replace("__APP_STYLESHEET__", &urls.stylesheet("styles"))
|
|
.replace("__APP_IMPORT_MAP__", &urls.import_map())
|
|
.replace("__APP_ENTRYPOINT__", &urls.entrypoint(entrypoint))
|
|
.replace(
|
|
"__REGISTRATION_ENABLED__",
|
|
if registration_enabled {
|
|
"true"
|
|
} else {
|
|
"false"
|
|
},
|
|
)
|
|
.replace("</head>", &format!("{frontend_config}</head>"));
|
|
|
|
let mut response = Html(html).into_response();
|
|
response.headers_mut().insert(
|
|
header::CACHE_CONTROL,
|
|
HeaderValue::from_static("private, no-store"),
|
|
);
|
|
response
|
|
}
|
|
|
|
pub fn stylesheet_tag(asset_version: &str, name: &str) -> String {
|
|
AssetUrls::new(asset_version).stylesheet(name)
|
|
}
|
|
|
|
fn frontend_config(
|
|
frontend_log_level: &str,
|
|
upload_max_size_bytes: usize,
|
|
external_auth: bool,
|
|
) -> String {
|
|
format!(
|
|
r#"<script>window.__RUSTPAD_CONFIG__=Object.freeze({{frontendLogLevel:"{}",uploadMaxSizeBytes:{},externalAuth:{}}});</script>"#,
|
|
escape_js_string(frontend_log_level),
|
|
upload_max_size_bytes,
|
|
external_auth,
|
|
)
|
|
}
|
|
|
|
struct AssetUrls<'a> {
|
|
version: &'a str,
|
|
}
|
|
|
|
impl<'a> AssetUrls<'a> {
|
|
fn new(version: &'a str) -> Self {
|
|
Self { version }
|
|
}
|
|
|
|
fn url(&self, path: &str) -> String {
|
|
format!("/assets/{path}?v={}", self.version)
|
|
}
|
|
|
|
fn stylesheet(&self, name: &str) -> String {
|
|
format!(
|
|
r#"<link rel="stylesheet" href="{}">"#,
|
|
self.url(&format!("css/{name}.css"))
|
|
)
|
|
}
|
|
|
|
fn entrypoint(&self, name: &str) -> String {
|
|
format!(
|
|
r#"<script type="module" src="{}"></script>"#,
|
|
self.url(&format!("js/{name}.js"))
|
|
)
|
|
}
|
|
|
|
fn import_map(&self) -> String {
|
|
let imports = MODULES
|
|
.iter()
|
|
.map(|module| {
|
|
format!(
|
|
r#""@rustpad/{module}":"{}""#,
|
|
self.url(&format!("js/{module}.js"))
|
|
)
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.join(",");
|
|
|
|
format!(r#"<script type="importmap">{{"imports":{{{imports}}}}}</script>"#)
|
|
}
|
|
}
|
|
|
|
fn escape_js_string(value: &str) -> String {
|
|
value
|
|
.replace('\\', "\\\\")
|
|
.replace('"', "\\\"")
|
|
.replace('<', "\\u003c")
|
|
}
|