//! File previews (milestone 4): browser-native media (image/PDF/video/audio) //! and read-only CodeMirror for text/code. use std::sync::{Arc, Mutex}; use api_types::FileKind; use leptos::prelude::*; use wasm_bindgen::JsValue; use wasm_bindgen_futures::spawn_local; use web_sys::MouseEvent; use crate::api; use crate::cm; /// What kind of preview a file gets. #[derive(Clone, Copy, PartialEq, Eq)] pub enum PreviewKind { Image, Pdf, Video, Audio, Text, } /// Which viewer opens this entry, from the server's sniffed [`FileKind`]. /// `None` = nothing we can show in the browser (download only). pub fn preview_kind(kind: FileKind) -> Option { match kind { FileKind::Image => Some(PreviewKind::Image), FileKind::Pdf => Some(PreviewKind::Pdf), FileKind::Video => Some(PreviewKind::Video), FileKind::Audio => Some(PreviewKind::Audio), FileKind::Text => Some(PreviewKind::Text), FileKind::Dir | FileKind::Archive | FileKind::Binary => None, } } /// A file the user wants to preview. #[derive(Clone)] pub struct PreviewTarget { pub root_id: i64, /// Path relative to the root (e.g. "docs/a.txt"). pub path: String, /// Display name (used for the title + language detection). pub name: String, #[allow(dead_code)] pub size: u64, } /// The preview overlay. #[component] pub fn PreviewModal( target: PreviewTarget, kind: PreviewKind, close: Callback<()>, ) -> impl IntoView { let t = target; let url = match kind { PreviewKind::Text => String::new(), _ => api::preview_url(t.root_id, &t.path), }; let name = t.name.clone(); // Escape closes the preview. { let c = close; crate::util::owned_window_listener( leptos::ev::keydown, move |ev: web_sys::KeyboardEvent| { if ev.key() == "Escape" { c.run(()); } }, ); } view! {