feat: initial release v0.1.0
This commit is contained in:
149
electron/main.js
Normal file
149
electron/main.js
Normal file
@@ -0,0 +1,149 @@
|
||||
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 };
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user