diff --git a/src/lib/pages/DictationPage.svelte b/src/lib/pages/DictationPage.svelte index 6b0b146..53d4d82 100644 --- a/src/lib/pages/DictationPage.svelte +++ b/src/lib/pages/DictationPage.svelte @@ -637,17 +637,38 @@ activeTemplate = ""; } - function handleExport(format) { + async function handleExport(format) { if (!transcript) return; showExportMenu = false; const content = exportTranscript(transcript, segments, format); - const extMap = { vtt: "vtt", srt: "srt", md: "md", csv: "csv", html: "html" }; + const extMap = { txt: "txt", vtt: "vtt", srt: "srt", md: "md", csv: "csv", html: "html" }; const ext = extMap[format] || "txt"; + const defaultPath = `magnotia-${new Date().toISOString().slice(0, 10)}.${ext}`; + + if (hasTauriRuntime()) { + try { + const { save } = await import("@tauri-apps/plugin-dialog"); + const path = await save({ + title: `Export ${format.toUpperCase()} transcript`, + defaultPath, + filters: [{ name: format.toUpperCase(), extensions: [ext] }], + }); + if (!path) return; + await invoke("write_text_file_cmd", { path, contents: content }); + toasts.success(`Exported ${format.toUpperCase()} transcript`); + return; + } catch (err) { + console.error("dictation export failed", err); + error = `Export failed: ${typeof err === "string" ? err : err.message || err}`; + return; + } + } + const blob = new Blob([content], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = `magnotia-${new Date().toISOString().slice(0, 10)}.${ext}`; + a.download = defaultPath; a.click(); URL.revokeObjectURL(url); } diff --git a/src/lib/pages/FilesPage.svelte b/src/lib/pages/FilesPage.svelte index 80914de..9bc0e07 100644 --- a/src/lib/pages/FilesPage.svelte +++ b/src/lib/pages/FilesPage.svelte @@ -8,6 +8,7 @@ import Card from "$lib/components/Card.svelte"; import EmptyState from "$lib/components/EmptyState.svelte"; import { exportTranscript } from "$lib/utils/export.js"; + import { hasTauriRuntime } from "$lib/utils/runtime"; import { Upload } from 'lucide-svelte'; let fileTranscript = $state(""); @@ -132,17 +133,37 @@ } } - function handleExport(format) { + async function handleExport(format) { if (!fileTranscript) return; showExportMenu = false; const content = exportTranscript(fileTranscript, segments, format); - const extMap = { vtt: "vtt", srt: "srt", md: "md", csv: "csv", html: "html" }; + const extMap = { txt: "txt", vtt: "vtt", srt: "srt", md: "md", csv: "csv", html: "html" }; const ext = extMap[format] || "txt"; + const defaultPath = `magnotia-file-${new Date().toISOString().slice(0, 10)}.${ext}`; + + if (hasTauriRuntime()) { + try { + const { save } = await import("@tauri-apps/plugin-dialog"); + const path = await save({ + title: `Export ${format.toUpperCase()} transcript`, + defaultPath, + filters: [{ name: format.toUpperCase(), extensions: [ext] }], + }); + if (!path) return; + await invoke("write_text_file_cmd", { path, contents: content }); + return; + } catch (err) { + console.error("file transcript export failed", err); + error = `Export failed: ${typeof err === "string" ? err : err.message || err}`; + return; + } + } + const blob = new Blob([content], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = `magnotia-file-${new Date().toISOString().slice(0, 10)}.${ext}`; + a.download = defaultPath; a.click(); URL.revokeObjectURL(url); } diff --git a/src/lib/utils/saveMarkdown.ts b/src/lib/utils/saveMarkdown.ts index bd88540..54ed09b 100644 --- a/src/lib/utils/saveMarkdown.ts +++ b/src/lib/utils/saveMarkdown.ts @@ -33,14 +33,24 @@ export function suggestedFilename(item: TranscriptEntry): string { export async function saveTranscriptAsMarkdown( item: TranscriptEntry, ): Promise { - if (!hasTauriRuntime()) return null; + if (!hasTauriRuntime()) { + toasts.error("Export unavailable", "Native save dialogs are only available in the desktop app."); + return null; + } const md = buildMarkdown(item); const defaultPath = suggestedFilename(item); - const path = await save({ - title: "Save transcript as Markdown", - defaultPath, - filters: [{ name: "Markdown", extensions: ["md"] }], - }); + let path: string | null = null; + try { + path = await save({ + title: "Save transcript as Markdown", + defaultPath, + filters: [{ name: "Markdown", extensions: ["md"] }], + }); + } catch (err) { + console.error("saveTranscriptAsMarkdown dialog failed", err); + toasts.error("Couldn't open save dialog", String(err)); + return null; + } if (!path) return null; try { await invoke("write_text_file_cmd", { path, contents: md }); @@ -64,13 +74,24 @@ export async function saveTranscriptAsMarkdown( export async function exportTranscriptsToDir( items: TranscriptEntry[], ): Promise { - if (!hasTauriRuntime() || items.length === 0) return 0; + if (items.length === 0) return 0; + if (!hasTauriRuntime()) { + toasts.error("Export unavailable", "Native folder dialogs are only available in the desktop app."); + return 0; + } - const dir = await open({ - directory: true, - multiple: false, - title: "Choose export folder", - }); + let dir: string | string[] | null = null; + try { + dir = await open({ + directory: true, + multiple: false, + title: "Choose export folder", + }); + } catch (err) { + console.error("exportTranscriptsToDir dialog failed", err); + toasts.error("Couldn't open export folder dialog", String(err)); + return 0; + } if (!dir || typeof dir !== "string") return 0; const used = new Set();