diff --git a/index.js b/index.js new file mode 100644 index 0000000..e9321fa --- /dev/null +++ b/index.js @@ -0,0 +1,151 @@ +import { app, BrowserWindow, globalShortcut, ipcMain, protocol, net } from 'electron'; +import path from 'path' +import fs from 'fs' +import { fileURLToPath } from "url"; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const WINDOW_SHORTCUTS = [ + process.platform === "darwin" ? "Command+R" : "Control+R", + "\\" +]; + +class App { + devToolsOpened = false; + + createWindow({onTop = false}) { + + const win = new BrowserWindow({ + width: 1200, + height: 800, + frame: false, + show: false, + titleBarStyle: "customButtonsOnHover", + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + contextIsolation: true, + nodeIntegration: false, + webviewTag: true, + } + }); + + if(onTop) { + win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); // necessary for full screen + win.setAlwaysOnTop(true, 'screen-saver', 1); // necessary so it doesn't bring you back out of full screen when spawned + } + + protocol.handle('app', (request) => { + const url = new URL(request.url); + let filePath = path.join(__dirname, url.pathname); + + // if file doesn't exist, fall back to index.html + if(filePath.includes("desktoputil")) { + filePath = path.join(__dirname, 'desktoputil.js'); + } + else if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) { + filePath = path.join(__dirname, 'index.html'); + } + + return net.fetch(`file://${filePath}`); + }); + + win.loadURL('app://local/'); + + win.on("focus", () => { + win.setVibrancy("appearance-based"); // full colors + }); + + win.on("blur", () => { + win.setVibrancy("selection"); // dims colors + }); + + win.webContents.on('did-finish-load', () => { + win.show(); + }); + + win.webContents.on('did-fail-load', (e, code, desc) => { + console.log('Webview failed:', desc); + }); + + win.on('closed', () => { + for (const key of WINDOW_SHORTCUTS) { + globalShortcut.unregister(key); + } + }); + } + + toggleDevTools(win) { + if (this.devToolsOpened) { + win.closeDevTools(); + } else { + win.openDevTools(); + } + this.devToolsOpened = !this.devToolsOpened; + } + + registerShortcuts() { + globalShortcut.register('CommandOrControl+Shift+Space', function CreateWindow() { + this.createWindow({onTop: true}); + }); + + app.on("browser-window-focus", function RegisterWindowOnFocus() { + const focused = BrowserWindow.getFocusedWindow(); + if (!focused) return; + + let WINDOW_SHORTCUTS = [ + process.platform === "darwin" ? "Command+R" : "Control+R", + "\\" + ]; + + // Reload + globalShortcut.register(WINDOW_SHORTCUTS[0], () => { + focused.reload(); + }); + + // Devtools + globalShortcut.register(WINDOW_SHORTCUTS[1], () => { + toggleDevTools(focused); + }); + }); + + app.on("browser-window-blur", function UnregisterWindowOnUnfocus() { + for (const key of WINDOW_SHORTCUTS) { + globalShortcut.unregister(key); + } + }); + } + + + constructor() { + app.on("activate", () => { + if (BrowserWindow.getAllWindows().length === 0) { + this.createWindow({onTop: false}); + } + }); + + app.on('window-all-closed', () => { + if (process.platform !== 'darwin') app.quit(); + }); + + app.on("ready", async () => { + this.createWindow({onTop: false}); + this.registerShortcuts() + }); + + ipcMain.on('focus-window', () => { + const win = BrowserWindow.getAllWindows()[0]; + win?.show(); + win?.focus(); + }); + + ipcMain.on('set-badge', (e, count) => { + app.setBadgeCount(count); + }); + + protocol.registerSchemesAsPrivileged([ + { scheme: 'app', privileges: { standard: true, secure: true, supportFetchAPI: true, corsEnabled: true } } + ]); + } +} + +new App() \ No newline at end of file