var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // electron/main.ts import { app, BrowserWindow as BrowserWindow3, shell, ipcMain, dialog as dialog2, nativeTheme, globalShortcut, clipboard } from "electron"; import path2 from "path"; import { fileURLToPath, pathToFileURL } from "url"; import fs2 from "fs"; import log2 from "electron-log"; // electron/services/pdfGenerator.ts import { BrowserWindow } from "electron"; async function generatePdf(htmlContent) { const printWin = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: false // 与 main.ts 保持一致,确保脚本执行权限 } }); try { await printWin.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(htmlContent)}`); await printWin.webContents.executeJavaScript(` new Promise(resolve => { const check = () => { if (window.__PRINT_READY__) { resolve(); } else { setTimeout(check, 100); } } check(); }) `); const pdfData = await printWin.webContents.printToPDF({ printBackground: true, pageSize: "A4", margins: { top: 0, bottom: 0, left: 0, right: 0 } }); return pdfData; } finally { printWin.close(); } } // electron/services/htmlImport.ts import { dialog } from "electron"; import path from "path"; import fs from "fs"; import log from "electron-log"; var selectHtmlFile = async (win) => { if (!win) return { success: false, error: "No window found" }; try { const { filePaths, canceled } = await dialog.showOpenDialog(win, { title: "\u9009\u62E9 HTML \u6587\u4EF6", filters: [ { name: "HTML Files", extensions: ["html", "htm"] } ], properties: ["openFile"] }); if (canceled || filePaths.length === 0) { return { success: false, canceled: true }; } const htmlPath = filePaths[0]; const htmlDir = path.dirname(htmlPath); const htmlFileName = path.basename(htmlPath, path.extname(htmlPath)); const assetsDirName = `${htmlFileName}_files`; const assetsDirPath = path.join(htmlDir, assetsDirName); const assetsFiles = []; if (fs.existsSync(assetsDirPath)) { const collectFiles = (dir, baseDir) => { const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { collectFiles(fullPath, baseDir); } else { const relPath = path.relative(baseDir, fullPath); assetsFiles.push(relPath); } } }; collectFiles(assetsDirPath, assetsDirPath); } return { success: true, htmlPath, htmlDir, htmlFileName, assetsDirName, assetsFiles }; } catch (error) { log.error("Select HTML file failed:", error); return { success: false, error: error.message }; } }; // electron/state.ts var ElectronState = class { constructor() { __publicField(this, "state", { mainWindow: null, serverPort: 3001, isDev: false }); } getMainWindow() { return this.state.mainWindow; } setMainWindow(window) { this.state.mainWindow = window; } getServerPort() { return this.state.serverPort; } setServerPort(port) { this.state.serverPort = port; } isDevelopment() { return this.state.isDev; } setDevelopment(isDev) { this.state.isDev = isDev; } reset() { this.state = { mainWindow: null, serverPort: 3001, isDev: false }; } }; var electronState = new ElectronState(); // electron/main.ts log2.initialize(); var __filename = fileURLToPath(import.meta.url); var __dirname = path2.dirname(__filename); process.env.NOTEBOOK_ROOT = path2.join(app.getPath("documents"), "XCDesktop"); if (!fs2.existsSync(process.env.NOTEBOOK_ROOT)) { try { fs2.mkdirSync(process.env.NOTEBOOK_ROOT, { recursive: true }); } catch (err) { log2.error("Failed to create notebook directory:", err); } } electronState.setDevelopment(!app.isPackaged); var lastClipboardText = ""; function startClipboardWatcher() { lastClipboardText = clipboard.readText(); setInterval(() => { try { const currentText = clipboard.readText(); if (currentText && currentText !== lastClipboardText) { lastClipboardText = currentText; log2.info("Clipboard changed, syncing to remote"); const win = electronState.getMainWindow(); if (win) { win.webContents.send("remote-clipboard-auto-sync", currentText); } } } catch (e) { } }, 1e3); } async function createWindow() { const initialSymbolColor = nativeTheme.shouldUseDarkColors ? "#ffffff" : "#000000"; const mainWindow = new BrowserWindow3({ width: 1280, height: 800, minWidth: 1600, minHeight: 900, autoHideMenuBar: true, titleBarStyle: "hidden", titleBarOverlay: { color: "#00000000", symbolColor: initialSymbolColor, height: 32 }, webPreferences: { nodeIntegration: false, contextIsolation: true, sandbox: false, webviewTag: true, preload: path2.join(__dirname, "preload.cjs") } }); electronState.setMainWindow(mainWindow); mainWindow.setMenu(null); mainWindow.webContents.setWindowOpenHandler(({ url }) => { if (url.startsWith("http:") || url.startsWith("https:")) { shell.openExternal(url); return { action: "deny" }; } return { action: "allow" }; }); if (electronState.isDevelopment()) { log2.info("Loading development URL..."); try { await mainWindow.loadURL("http://localhost:5173"); } catch (e) { log2.error("Failed to load dev URL. Make sure npm run electron:dev is used.", e); } mainWindow.webContents.openDevTools(); } else { log2.info(`Loading production URL with port ${electronState.getServerPort()}...`); await mainWindow.loadURL(`http://localhost:${electronState.getServerPort()}`); } } ipcMain.handle("export-pdf", async (event, title, htmlContent) => { const win = BrowserWindow3.fromWebContents(event.sender); if (!win) return { success: false, error: "No window found" }; try { const { filePath } = await dialog2.showSaveDialog(win, { title: "\u5BFC\u51FA PDF", defaultPath: `${title}.pdf`, filters: [{ name: "PDF Files", extensions: ["pdf"] }] }); if (!filePath) return { success: false, canceled: true }; if (!htmlContent) { throw new Error("No HTML content provided for PDF export"); } const pdfData = await generatePdf(htmlContent); fs2.writeFileSync(filePath, pdfData); return { success: true, filePath }; } catch (error) { log2.error("Export PDF failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("select-html-file", async (event) => { const win = BrowserWindow3.fromWebContents(event.sender); return selectHtmlFile(win); }); ipcMain.handle("update-titlebar-buttons", async (event, symbolColor) => { const win = BrowserWindow3.fromWebContents(event.sender); if (win) { win.setTitleBarOverlay({ symbolColor }); return { success: true }; } return { success: false }; }); ipcMain.handle("clipboard-read-text", async () => { try { const text = clipboard.readText(); return { success: true, text }; } catch (error) { log2.error("Clipboard read failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("clipboard-write-text", async (event, text) => { try { clipboard.writeText(text); return { success: true }; } catch (error) { log2.error("Clipboard write failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("remote-fetch-drives", async (_event, serverHost, port, password) => { try { let url = `http://${serverHost}:${port}/api/files/drives`; if (password) { url += `?password=${encodeURIComponent(password)}`; } const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch drives: ${response.statusText}`); } const data = await response.json(); const items = data.items || []; return { success: true, data: items.map((item) => ({ name: item.name, path: item.name, type: item.isDirectory ? "dir" : "file", size: item.size, modified: "" })) }; } catch (error) { log2.error("Remote fetch drives failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("remote-fetch-files", async (_event, serverHost, port, filePath, password) => { try { let url = `http://${serverHost}:${port}/api/files/browse?path=${encodeURIComponent(filePath)}&allowSystem=true`; if (password) { url += `&password=${encodeURIComponent(password)}`; } const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to fetch files: ${response.statusText}`); } const data = await response.json(); const items = data.items || []; return { success: true, data: items.map((item) => ({ name: item.name, path: data.currentPath ? `${data.currentPath}/${item.name}` : item.name, type: item.isDirectory ? "dir" : "file", size: item.size, modified: item.modified?.toString() })) }; } catch (error) { log2.error("Remote fetch files failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("remote-upload-file", async (_event, serverHost, port, filePath, remotePath, password) => { try { const win = electronState.getMainWindow(); if (!win) { throw new Error("No window found"); } const fullPath = path2.resolve(filePath); if (!fs2.existsSync(fullPath)) { throw new Error("File not found"); } const fileBuffer = fs2.readFileSync(fullPath); const fileName = path2.basename(fullPath); let url = `http://${serverHost}:${port}/api/files/upload`; if (password) { url += `?password=${encodeURIComponent(password)}`; } const formData = new FormData(); const blob = new Blob([fileBuffer]); formData.append("file", blob, fileName); if (remotePath) { formData.append("path", remotePath); } const response = await fetch(url, { method: "POST", body: formData }); if (!response.ok) { throw new Error(`Upload failed: ${response.statusText}`); } return { success: true }; } catch (error) { log2.error("Remote upload failed:", error); return { success: false, error: error.message }; } }); ipcMain.handle("remote-download-file", async (_event, serverHost, port, fileName, remotePath, password) => { try { const win = electronState.getMainWindow(); if (!win) { throw new Error("No window found"); } let url = `http://${serverHost}:${port}/api/files/${encodeURIComponent(fileName)}`; if (password) { url += `?password=${encodeURIComponent(password)}`; } const response = await fetch(url); if (!response.ok) { throw new Error(`Download failed: ${response.statusText}`); } const buffer = await response.arrayBuffer(); const { filePath } = await dialog2.showSaveDialog(win, { title: "\u4FDD\u5B58\u6587\u4EF6", defaultPath: fileName }); if (!filePath) { return { success: false, canceled: true }; } fs2.writeFileSync(filePath, Buffer.from(buffer)); return { success: true, filePath }; } catch (error) { log2.error("Remote download failed:", error); return { success: false, error: error.message }; } }); async function startServer() { if (electronState.isDevelopment()) { log2.info("In dev mode, assuming external servers are running."); return; } const serverPath = path2.join(__dirname, "../dist-api/server.js"); const serverUrl = pathToFileURL(serverPath).href; log2.info(`Starting internal server from: ${serverPath}`); try { const serverModule = await import(serverUrl); if (serverModule.startServer) { const port = await serverModule.startServer(); electronState.setServerPort(port); log2.info(`Internal server started successfully on port ${port}`); } else { log2.warn("startServer function not found in server module, using default port 3001"); } } catch (e) { log2.error("Failed to start internal server:", e); } } app.whenReady().then(async () => { await startServer(); await createWindow(); startClipboardWatcher(); globalShortcut.register("CommandOrControl+Shift+C", () => { log2.info("Global shortcut: sync clipboard to remote"); const win = electronState.getMainWindow(); if (win) { win.webContents.send("remote-clipboard-sync-to-remote"); } }); globalShortcut.register("CommandOrControl+Shift+V", () => { log2.info("Global shortcut: sync clipboard from remote"); const win = electronState.getMainWindow(); if (win) { win.webContents.send("remote-clipboard-sync-from-remote"); } }); app.on("activate", () => { if (BrowserWindow3.getAllWindows().length === 0) { createWindow(); } }); }); app.on("window-all-closed", () => { globalShortcut.unregisterAll(); if (process.platform !== "darwin") { app.quit(); } }); //# sourceMappingURL=main.js.map