mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-30 13:08:48 -06:00
Co-authored-by: Tevinhead <173904641+Tevinhead@users.noreply.github.com> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
87 lines
3.9 KiB
Rust
87 lines
3.9 KiB
Rust
//! 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::<web_sys::HtmlCanvasElement>().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=<url>` opens a PDF from a URL (same-origin or CORS-enabled).
|
|
if let Some(url) = query_param("file") {
|
|
let inbox = app.startup_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<String> {
|
|
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<Vec<u8>, 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");
|
|
}
|