This commit is contained in:
Mateusz Gruszczyński committed 2026-10-16 22:49:22 +02:00
1 parent 4da41a1404
commit 5cb6960b04
31 files changed
+1611 -2123

No files matched your search

+50 -3
View File
@@ -48,6 +48,7 @@ const MODULES: &[&str] = &[
"theme",
"url-state",
"vendor-libs",
"virtual-editor-layers",
"security",
"select",
];
@@ -73,8 +74,18 @@ pub fn render_html(
urls.stylesheet("styles"),
urls.stylesheet_path("libs/rustpad-player/player.css"),
);
let show_note_loader = matches!(entrypoint, "pad" | "note");
let html = template
.replace("__APP_THEME_BOOTSTRAP__", &format!("{}{}", theme_bootstrap(), language_bootstrap()))
.replace(
"__APP_THEME_BOOTSTRAP__",
&format!(
"{}{}{}",
theme_bootstrap(),
language_bootstrap(),
if show_note_loader { loading_bootstrap() } else { String::new() }
),
)
.replace("__APP_LOADING_OVERLAY__", if show_note_loader { loading_overlay() } else { "" })
.replace("__APP_STYLESHEET__", &app_stylesheets)
.replace("__APP_IMPORT_MAP__", &urls.import_map())
.replace("__APP_ENTRYPOINT__", &urls.entrypoint(entrypoint))
@@ -101,6 +112,39 @@ pub fn render_html(
response
}
fn loading_bootstrap() -> String {
// Embedded critical CSS and controller are available before the external assets.
format!(
"<style>{}</style><script>{}</script>",
include_str!("../static/css/boot-loading.css"),
include_str!("../static/js/boot-loading.js"),
)
}
fn loading_overlay() -> &'static str {
r#"<div id="app-boot-overlay" role="status" aria-live="polite" aria-label="Loading RustPad">
<div class="app-boot-card">
<div class="app-boot-brand" aria-label="RustPad" role="img">
<span class="app-boot-wordmark" aria-hidden="true">RustPad</span>
</div>
<h2 id="app-boot-heading">Loading…</h2>
<p id="app-boot-stage">Preparing the interface</p>
<div id="app-boot-progress" class="app-boot-track" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-label="Startup progress">
<div id="app-boot-progress-fill"></div>
</div>
<p id="app-boot-count">0 of 5 stages completed</p>
<ol class="app-boot-steps" aria-label="Loading stages">
<li id="app-boot-step-assets"><span>Interface</span></li>
<li id="app-boot-step-language"><span>Language</span></li>
<li id="app-boot-step-libraries"><span>Editor</span></li>
<li id="app-boot-step-access"><span>Access</span></li>
<li id="app-boot-step-files"><span>Note</span></li>
</ol>
<button type="button" id="app-boot-retry" hidden>Reload page</button>
</div>
</div>"#
}
pub fn theme_bootstrap() -> &'static str {
r#"<script>(()=>{const key="rustpad:theme",guestKey="rustpad:guest-theme",authKey="rustpad:auth-state";let theme=matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";try{const signedIn=localStorage.getItem(authKey)==="1";const saved=signedIn?localStorage.getItem(key):(localStorage.getItem(guestKey)||localStorage.getItem(key));if(saved==="light"||saved==="dark")theme=saved}catch{}const root=document.documentElement;root.dataset.theme=theme;root.style.colorScheme=theme;const meta=document.querySelector('meta[name="color-scheme"]');if(meta)meta.content=theme})();</script>"#
}
@@ -154,13 +198,16 @@ impl<'a> AssetUrls<'a> {
}
fn stylesheet_path(&self, path: &str) -> String {
format!(r#"<link rel="stylesheet" href="{}">"#, self.url(path))
format!(
r#"<link rel="stylesheet" data-rustpad-shell-css href="{}">"#,
self.url(path)
)
}
fn entrypoint(&self, name: &str) -> String {
let entrypoint = self.url(&format!("js/{name}.js"));
format!(
r#"<script type="module">import {{ initI18n }} from "@rustpad/i18n";import {{ initHeaderPreferences }} from "@rustpad/preferences";import {{ initSelectControls }} from "@rustpad/select";await initI18n();initHeaderPreferences();await import("{}");initSelectControls();</script>"#,
r#"<script type="module">const boot=window.__RUSTPAD_LOADING__;try{{const [i18n,prefs,select]=await Promise.all([import("@rustpad/i18n"),import("@rustpad/preferences"),import("@rustpad/select")]);boot?.complete("js");await i18n.initI18n();boot?.complete("language");prefs.initHeaderPreferences();await import("{}");select.initSelectControls();boot?.complete("libraries");}}catch(error){{console.error("RustPad startup failed",error);boot?.fail(error);}}</script>"#,
escape_js_string(&entrypoint)
)
}
+2 -5
View File
@@ -174,7 +174,7 @@ impl Config {
"GUEST_UPLOAD_MAX_SIZE_MB",
guest_upload_max_size_mb,
)?,
asset_version: env!("CARGO_PKG_VERSION").to_owned(),
asset_version: format!("{}-ui3", env!("CARGO_PKG_VERSION")),
http_compression: values.bool("HTTP_COMPRESSION", false)?,
asset_cache_max_age_seconds: values
.nonnegative_u64("ASSET_CACHE_MAX_AGE_SECONDS", 600)?,
@@ -241,10 +241,7 @@ fn multipart_body_limit_bytes(
file_limit.saturating_add(1024 * 1024)
}
fn megabytes_to_bytes(
name: &str,
megabytes: u64,
) -> Result<usize, Box<dyn std::error::Error>> {
fn megabytes_to_bytes(name: &str, megabytes: u64) -> Result<usize, Box<dyn std::error::Error>> {
let bytes = megabytes
.checked_mul(1024 * 1024)
.ok_or_else(|| format!("{name} is too large"))?;