1pub use blockworx_export::{ExportContent, bytes_for};
12pub use blockworx_tools::commands::{ExportFormat, ExportScope};
18
19fn format(content: &ExportContent) -> ExportFormat {
21 match content {
22 ExportContent::Svg(_) => ExportFormat::Svg,
23 ExportContent::Png(_) => ExportFormat::Png,
24 ExportContent::Pdf(_) => ExportFormat::Pdf,
25 }
26}
27
28#[cfg(not(target_arch = "wasm32"))]
30fn filter_name(format: ExportFormat) -> &'static str {
31 match format {
32 ExportFormat::Svg => "SVG image",
33 ExportFormat::Png => "PNG image",
34 ExportFormat::Pdf => "PDF document",
35 }
36}
37
38#[cfg(target_arch = "wasm32")]
40fn mime(format: ExportFormat) -> &'static str {
41 match format {
42 ExportFormat::Svg => "image/svg+xml",
43 ExportFormat::Png => "image/png",
44 ExportFormat::Pdf => "application/pdf",
45 }
46}
47
48pub struct ExportPayload {
52 pub name: String,
53 pub content: ExportContent,
54}
55
56#[cfg(not(target_arch = "wasm32"))]
63pub fn spawn_export(ctx: &egui::Context, payload: ExportPayload) {
64 let thread_ctx = ctx.clone();
65 std::thread::spawn(move || {
66 let format = format(&payload.content);
67 let ext = format.extension();
68 let picked = rfd::FileDialog::new()
69 .set_file_name(format!("{}.{ext}", payload.name))
70 .add_filter(filter_name(format), &[ext])
71 .save_file();
72 if let Some(path) = picked {
73 let named = crate::file::container_name(&path);
74 match blockworx_store::atomic::write_atomically(&path, &bytes_for(&payload.content)) {
75 Ok(()) => crate::shell::status_line::say(&thread_ctx, format!("Exported {named}")),
76 Err(e) => {
77 tracing::error!("Failed to export {}: {e}", path.display());
78 crate::shell::toast::say(&thread_ctx, format!("Could not export {named}: {e}"));
79 }
80 }
81 }
82 thread_ctx.request_repaint();
83 });
84 ctx.request_repaint();
85}
86
87#[expect(clippy::needless_pass_by_value)]
94#[cfg(target_arch = "wasm32")]
95pub fn spawn_export(ctx: &egui::Context, payload: ExportPayload) {
96 let format = format(&payload.content);
97 let name = format!("{}.{}", payload.name, format.extension());
98 match blockworx_canvas2d::download(&name, mime(format), &bytes_for(&payload.content)) {
99 Ok(()) => crate::shell::status_line::say(ctx, format!("Exported {name}")),
100 Err(e) => {
101 web_sys::console::error_1(&format!("Failed to export {name}: {e:?}").into());
102 crate::shell::toast::say(ctx, format!("Could not export {name}"));
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::{ExportFormat, ExportScope};
110
111 #[test]
114 fn only_the_view_offers_pdf() {
115 assert!(ExportScope::View.formats().contains(&ExportFormat::Pdf));
116 assert!(
117 !ExportScope::Selection
118 .formats()
119 .contains(&ExportFormat::Pdf)
120 );
121 for format in ExportScope::Selection.formats() {
122 assert!(
123 ExportScope::View.formats().contains(format),
124 "{format:?} is offered on a selection but not on the view",
125 );
126 }
127 }
128}