63 lines
2.2 KiB
Rust
63 lines
2.2 KiB
Rust
//! PDF viewer tab: embeds the Tauri-served PDF viewer in an iframe.
|
|
//!
|
|
//! The custom `brittle://` URI scheme serves:
|
|
//! - `brittle://app/viewer?ref_id=<uuid>` — the viewer HTML page (PDF.js)
|
|
//! - `brittle://app/pdf?ref_id=<uuid>` — the raw PDF bytes
|
|
//!
|
|
//! Using an `<iframe>` keeps the viewer alive when the tab is hidden (via
|
|
//! `display:none`), so scrolling position and zoom are preserved across
|
|
//! tab switches.
|
|
|
|
use brittle_keymap::actions;
|
|
use leptos::prelude::*;
|
|
use wasm_bindgen::JsValue;
|
|
|
|
/// Renders the PDF viewer for a single reference.
|
|
///
|
|
/// `ref_id` must be the UUID string of a reference that has an attached PDF.
|
|
/// `is_active` indicates whether this is the currently visible PDF tab; when
|
|
/// `true`, keymap actions for PDF page navigation are forwarded into the iframe.
|
|
#[component]
|
|
pub fn PdfViewer(
|
|
ref_id: String,
|
|
is_active: Signal<bool>,
|
|
initial_zoom: Option<f64>,
|
|
initial_scroll_top: Option<f64>,
|
|
) -> impl IntoView {
|
|
let mut url = format!("brittle://app/viewer?ref_id={ref_id}");
|
|
if let Some(z) = initial_zoom { url.push_str(&format!("&zoom={z}")); }
|
|
if let Some(s) = initial_scroll_top { url.push_str(&format!("&scroll_top={s}")); }
|
|
|
|
let iframe_ref = NodeRef::<leptos::html::Iframe>::new();
|
|
|
|
let keymap_action = use_context::<crate::KeymapAction>()
|
|
.expect("KeymapAction context missing")
|
|
.0;
|
|
|
|
Effect::new(move |_| {
|
|
let Some(ev) = keymap_action.get() else { return };
|
|
if !is_active.get_untracked() { return }
|
|
|
|
let cmd = match ev.name.as_str() {
|
|
actions::PDF_PAGE_NEXT => actions::PDF_PAGE_NEXT,
|
|
actions::PDF_PAGE_PREV => actions::PDF_PAGE_PREV,
|
|
_ => return,
|
|
};
|
|
|
|
let Some(iframe) = iframe_ref.get() else { return };
|
|
if let Some(win) = iframe.content_window() {
|
|
let _ = win.post_message(&JsValue::from_str(cmd), "*");
|
|
}
|
|
});
|
|
|
|
view! {
|
|
<iframe
|
|
node_ref=iframe_ref
|
|
class="pdf-frame"
|
|
src=url
|
|
// Intentionally no `sandbox` attribute — the brittle:// protocol
|
|
// and PDF.js require unrestricted access within the webview.
|
|
/>
|
|
}
|
|
}
|