import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import { fileURLToPath } from 'url'; import path from 'path'; import fs from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const SETTINGS_FILE = path.join(app.getPath('userData'), 'settings.json'); let mainWindow; function loadSettings() { try { if (fs.existsSync(SETTINGS_FILE)) { return JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf-8')); } } catch (err) { console.error('Failed to load settings:', err); } return {}; } function saveSettings(settings) { try { const current = loadSettings(); const updated = { ...current, ...settings }; fs.writeFileSync(SETTINGS_FILE, JSON.stringify(updated, null, 2)); } catch (err) { console.error('Failed to save settings:', err); } } function createWindow() { const settings = loadSettings(); const windowBounds = settings.windowBounds || { width: 1200, height: 800 }; mainWindow = new BrowserWindow({ x: windowBounds.x, y: windowBounds.y, width: windowBounds.width, height: windowBounds.height, minWidth: 1000, minHeight: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }); const isDev = process.env.NODE_ENV === 'development'; if (isDev) { mainWindow.loadURL('http://localhost:5173'); mainWindow.webContents.openDevTools(); } else { // In production, use app.getAppPath() to correctly resolve the ASAR root const appPath = app.getAppPath(); mainWindow.loadFile(path.join(appPath, 'dist/index.html')); } // Persist window bounds on change const saveBounds = () => { const bounds = mainWindow.getBounds(); saveSettings({ windowBounds: bounds }); }; mainWindow.on('resize', saveBounds); mainWindow.on('move', saveBounds); } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); // Settings Handlers ipcMain.handle('get-settings', async () => { return loadSettings(); }); ipcMain.handle('update-settings', async (event, settings) => { saveSettings(settings); return { success: true }; }); // IPC Handler for Image Export // IPC Handler for Image/PDF/HTML Export ipcMain.handle('save-image', async (event, dataUrl, format) => { const isPdf = format === 'pdf'; const isHtml = format === 'html'; let filters = [{ name: 'Images', extensions: [format] }]; if (isPdf) filters = [{ name: 'PDF Documents', extensions: ['pdf'] }]; if (isHtml) filters = [{ name: 'HTML Files', extensions: ['html'] }]; const { canceled, filePath } = await dialog.showSaveDialog(mainWindow, { title: isPdf ? 'Save PDF' : (isHtml ? 'Save HTML' : 'Save Image'), defaultPath: `export.${format}`, filters: filters, }); if (canceled || !filePath) { return { success: false, message: 'Cancelled' }; } // Remove header (e.g., "data:image/png;base64," or "data:application/pdf;base64," or "data:text/html;base64,") const base64Data = dataUrl.replace(/^data:(image\/\w+|application\/pdf|text\/html);base64,/, ''); try { fs.writeFileSync(filePath, base64Data, 'base64'); return { success: true, filePath }; } catch (error) { console.error('Failed to save file:', error); return { success: false, message: error.message }; } }); // IPC Handler for HTML Import ipcMain.handle('open-file', async () => { const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, { title: 'Open HTML File', filters: [{ name: 'HTML Files', extensions: ['html'] }], properties: ['openFile'] }); if (canceled || filePaths.length === 0) { return { success: false, message: 'Cancelled' }; } try { const content = fs.readFileSync(filePaths[0], 'utf-8'); return { success: true, content, filePath: filePaths[0] }; } catch (error) { console.error('Failed to open file:', error); return { success: false, message: error.message }; } });