109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
import { app, BrowserWindow, ipcMain, dialog, Menu, nativeTheme } from "electron"
|
|
import { join, dirname } from "node:path"
|
|
import { fileURLToPath } from "node:url"
|
|
import { readFileSync, writeFileSync } from "node:fs"
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
|
|
process.env.DIST = join(__dirname, "../dist")
|
|
process.env.VITE_PUBLIC = app.isPackaged
|
|
? process.env.DIST
|
|
: join(process.env.DIST, "../public")
|
|
|
|
let win: BrowserWindow | null
|
|
const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"]
|
|
|
|
app.disableHardwareAcceleration()
|
|
app.commandLine.appendSwitch("disable-direct-composition")
|
|
|
|
Menu.setApplicationMenu(null)
|
|
|
|
function createWindow() {
|
|
win = new BrowserWindow({
|
|
width: 1480,
|
|
height: 880,
|
|
minWidth: 1024,
|
|
minHeight: 600,
|
|
frame: false,
|
|
webPreferences: {
|
|
preload: join(__dirname, "preload.js"),
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
},
|
|
show: false,
|
|
})
|
|
|
|
win.on("ready-to-show", () => {
|
|
win?.show()
|
|
win?.focus()
|
|
})
|
|
|
|
win.on("maximize", () => win?.webContents?.send("window:maximize-change", true))
|
|
win.on("unmaximize", () => win?.webContents?.send("window:maximize-change", false))
|
|
win.on("enter-full-screen", () => win?.webContents?.send("window:maximize-change", true))
|
|
win.on("leave-full-screen", () => win?.webContents?.send("window:maximize-change", false))
|
|
|
|
if (VITE_DEV_SERVER_URL) {
|
|
win.loadURL(VITE_DEV_SERVER_URL)
|
|
} else {
|
|
win.loadFile(join(process.env.DIST!, "index.html"))
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// ── IPC Handlers ──
|
|
|
|
ipcMain.on("window:focus", () => win?.focus())
|
|
ipcMain.on("window:setTheme", (_event, dark: boolean) => { nativeTheme.themeSource = dark ? "dark" : "light" })
|
|
ipcMain.on("window:minimize", () => win?.minimize())
|
|
ipcMain.on("window:maximize", () => { if (win?.isMaximized()) win.unmaximize(); else win?.maximize() })
|
|
ipcMain.on("window:close", () => win?.close())
|
|
ipcMain.handle("window:isMaximized", () => win?.isMaximized())
|
|
ipcMain.handle("dialog:openFile", async (_event, filters: { name: string; extensions: string[] }[]) => {
|
|
const result = await dialog.showOpenDialog(win!, {
|
|
properties: ["openFile"],
|
|
filters,
|
|
})
|
|
win?.webContents?.focus()
|
|
return result.filePaths
|
|
})
|
|
|
|
ipcMain.handle("dialog:saveFile", async (_event, defaultName: string, filters: { name: string; extensions: string[] }[]) => {
|
|
const result = await dialog.showSaveDialog(win!, {
|
|
defaultPath: defaultName,
|
|
filters,
|
|
})
|
|
win?.webContents?.focus()
|
|
return result.filePath ?? ""
|
|
})
|
|
|
|
ipcMain.handle("file:read", async (_event, path: string) => {
|
|
return readFileSync(path, "utf-8")
|
|
})
|
|
|
|
ipcMain.handle("file:write", async (_event, path: string, data: string) => {
|
|
writeFileSync(path, data, "utf-8")
|
|
})
|
|
|
|
ipcMain.handle("file:readImage", async (_event, path: string) => {
|
|
const buffer = readFileSync(path)
|
|
const ext = path.split(".").pop()?.toLowerCase() ?? "png"
|
|
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png"
|
|
return `data:${mime};base64,${buffer.toString("base64")}`
|
|
})
|
|
|
|
ipcMain.handle("file:writeBinary", async (_event, path: string, base64: string) => {
|
|
writeFileSync(path, Buffer.from(base64, "base64"))
|
|
})
|
|
|
|
app.whenReady().then(createWindow)
|
|
|
|
app.on("window-all-closed", () => {
|
|
if (process.platform !== "darwin") app.quit()
|
|
})
|
|
|
|
app.on("activate", () => {
|
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
|
})
|