//! PdfCraft in the browser. Build: `cd apps/pdfcraft-web && trunk build --release` //! (trunk generates the JS loader; no handwritten JS — plan/execution-plan.md §1). #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #[cfg(target_arch = "wasm32")] fn main() { use eframe::wasm_bindgen::JsCast; use pdfcraft_ui_egui::PdfCraftApp; let options = eframe::WebOptions { renderer: eframe::Renderer::Glow, ..Default::default() }; wasm_bindgen_futures::spawn_local(async move { let Some(canvas) = web_sys::window() .and_then(|w| w.document()) .and_then(|d| d.get_element_by_id("pdfcraft")) .and_then(|e| e.dyn_into::().ok()) else { return; }; let started = eframe::WebRunner::new() .start( canvas, options, Box::new(|cc| { let mut app = PdfCraftApp::new(); // "printcraft": settings saved under the app's former name, PrintCraft. if let Some(json) = cc.storage.and_then(|s| s.get_string("pdfcraft").or_else(|| s.get_string("printcraft"))) { app.restore(&json); } // `?file=` opens a PDF from a URL (same-origin or CORS-enabled). if let Some(url) = query_param("file") { let inbox = app.inbox.clone(); let failed = app.failed_inbox.clone(); let ctx = cc.egui_ctx.clone(); wasm_bindgen_futures::spawn_local(async move { let name = url.rsplit('/').next().unwrap_or("document.pdf").split('?').next().unwrap_or("document.pdf").to_string(); match fetch_bytes(&url).await { Ok(bytes) => { if let Ok(mut q) = inbox.lock() { q.push((name, bytes)); } } Err(e) => { eframe::web_sys::console::error_1(&format!("PdfCraft: could not fetch {url}: {e}").into()); // Shown in the app too, not only in the console (#173). if let Ok(mut q) = failed.lock() { q.push((name, e)); } } } ctx.request_repaint(); }); } Ok(Box::new(app)) }), ) .await; if let Err(e) = started { eframe::web_sys::console::error_1(&e); } }); } #[cfg(target_arch = "wasm32")] fn query_param(key: &str) -> Option { let search = web_sys::window()?.location().search().ok()?; web_sys::UrlSearchParams::new_with_str(&search).ok()?.get(key) } #[cfg(target_arch = "wasm32")] async fn fetch_bytes(url: &str) -> Result, String> { use eframe::wasm_bindgen::JsCast; let window = web_sys::window().ok_or("no window")?; let resp = wasm_bindgen_futures::JsFuture::from(window.fetch_with_str(url)).await.map_err(|e| format!("{e:?}"))?; let resp: web_sys::Response = resp.dyn_into().map_err(|_| "not a response")?; if !resp.ok() { return Err(format!("HTTP {}", resp.status())); } let buf = wasm_bindgen_futures::JsFuture::from(resp.array_buffer().map_err(|e| format!("{e:?}"))?).await.map_err(|e| format!("{e:?}"))?; Ok(js_sys::Uint8Array::new(&buf).to_vec()) } #[cfg(not(target_arch = "wasm32"))] fn main() { eprintln!("pdfcraft-web targets wasm32: run `trunk serve` or `trunk build --release` in apps/pdfcraft-web"); }