diff --git a/electron/main.ts b/electron/main.ts index 4f73d83..90f7c15 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1,5 +1,5 @@ import { app, BrowserWindow, Menu, dialog, ipcMain } from "electron"; -import type { OpenDialogOptions } from "electron"; +import type { OpenDialogOptions, SaveDialogOptions } from "electron"; import { readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { fileURLToPath } from "node:url"; @@ -55,11 +55,17 @@ ipcMain.handle("envhelper:open-file", async (event) => { }; }); -ipcMain.handle("envhelper:save-file", async (_event, content: string) => { - const result = await dialog.showSaveDialog({ +ipcMain.handle("envhelper:save-file", async (event, content: string) => { + const owner = BrowserWindow.fromWebContents(event.sender); + const options = { defaultPath: ".env", - filters: [{ name: "Environment file", extensions: ["env"] }] - }); + filters: [ + { name: "Environment files", extensions: ["env", "txt"] }, + { name: "All files", extensions: ["*"] } + ] + } satisfies SaveDialogOptions; + + const result = owner ? await dialog.showSaveDialog(owner, options) : await dialog.showSaveDialog(options); if (result.canceled || !result.filePath) { return null; diff --git a/src/App.tsx b/src/App.tsx index cc36272..b18663d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -473,6 +473,20 @@ function openFileWithBrowserPicker(): Promise<{ name: string; content: string } }); } +function saveFileWithBrowserDownload(content: string) { + const blob = new Blob([content], { type: "text/plain;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const anchor = document.createElement("a"); + anchor.href = url; + anchor.download = ".env"; + anchor.style.display = "none"; + + document.body.append(anchor); + anchor.click(); + anchor.remove(); + URL.revokeObjectURL(url); +} + export default function App() { const [input, setInput] = useState(""); const [loadedPath, setLoadedPath] = useState(null); @@ -534,7 +548,16 @@ export default function App() { } async function saveFile() { - await window.envHelper?.saveFile(result.output); + try { + if (window.envHelper?.saveFile) { + await window.envHelper.saveFile(result.output); + return; + } + } catch (error) { + console.warn("Native save dialog failed, falling back to browser download.", error); + } + + saveFileWithBrowserDownload(result.output); } async function copyOutput() {