Files

136 lines
4.2 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, existsSync, mkdirSync, copyFileSync, readdirSync } 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:openDirectory", async () => {
const result = await dialog.showOpenDialog(win!, {
properties: ["openDirectory"],
})
win?.webContents?.focus()
return result.filePaths?.[0] ?? ""
})
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"))
})
ipcMain.handle("dir:read", async (_event, dirPath: string) => {
if (!existsSync(dirPath)) return []
const entries = readdirSync(dirPath, { withFileTypes: true })
return entries.map((e) => ({ name: e.name, isDirectory: e.isDirectory() }))
})
ipcMain.handle("dir:ensure", async (_event, dirPath: string) => {
if (!existsSync(dirPath)) mkdirSync(dirPath, { recursive: true })
return dirPath
})
ipcMain.handle("path:exists", async (_event, path: string) => {
return existsSync(path)
})
ipcMain.handle("file:copy", async (_event, src: string, dest: string) => {
copyFileSync(src, dest)
})
app.whenReady().then(createWindow)
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit()
})
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})