From e0bfaeb2ebf4768ce97e3645a01ed12b0fe9d43e Mon Sep 17 00:00:00 2001 From: Vaibhaav Date: Sun, 19 Jul 2026 21:25:15 +0530 Subject: [PATCH] fix: support ctrl plus zoom accelerator --- frontend/src/main.ts | 33 ++----------------------------- frontend/src/main/menu.test.ts | 30 ++++++++++++++++++++++++++++ frontend/src/main/menu.ts | 36 ++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 frontend/src/main/menu.test.ts create mode 100644 frontend/src/main/menu.ts diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 340fd358bf..d3a9b428a8 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -56,6 +56,7 @@ import { connectSupervisor, type SupervisorLinkHandle } from "./main/supervisor- import { shouldLinkOnAttach } from "./main/daemon-owner"; import { readMigrationState, updateMigration, writeAppStateMarker, type MigrationState } from "./main/app-state"; import { isAllowedAppExternalURL, openAllowedAppExternalURL } from "./main/external-open"; +import { buildWindowsAppMenuTemplate } from "./main/menu"; // Globals injected at compile time by @electron-forge/plugin-vite. declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string | undefined; @@ -242,37 +243,7 @@ function setDaemonStatus(nextStatus: DaemonStatus): void { // DevTools, zoom, full screen, edit commands) and each acts on the *focused* // webContents — including a BrowserView panel — matching native menu behaviour. function buildWindowsAppMenu(): Menu { - return Menu.buildFromTemplate([ - { - label: "Edit", - submenu: [ - { role: "undo" }, - { role: "redo" }, - { type: "separator" }, - { role: "cut" }, - { role: "copy" }, - { role: "paste" }, - { role: "selectAll" }, - ], - }, - { - label: "View", - submenu: [ - { role: "reload" }, - { role: "toggleDevTools" }, - { type: "separator" }, - { role: "resetZoom" }, - { role: "zoomIn" }, - { role: "zoomOut" }, - { type: "separator" }, - { role: "togglefullscreen" }, - ], - }, - { - label: "Window", - submenu: [{ role: "minimize" }, { role: "close" }], - }, - ]); + return Menu.buildFromTemplate(buildWindowsAppMenuTemplate()); } function createWindow(): void { diff --git a/frontend/src/main/menu.test.ts b/frontend/src/main/menu.test.ts new file mode 100644 index 0000000000..95a12df818 --- /dev/null +++ b/frontend/src/main/menu.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import { buildWindowsAppMenuTemplate } from "./menu"; + +type MenuItem = ReturnType[number]; +type SubmenuItem = NonNullable>[number]; + +function viewSubmenu(): readonly SubmenuItem[] { + const viewMenu = buildWindowsAppMenuTemplate().find((item) => item.label === "View"); + if (!viewMenu || !Array.isArray(viewMenu.submenu)) { + throw new Error("View menu not found"); + } + return viewMenu.submenu; +} + +describe("buildWindowsAppMenuTemplate", () => { + it("registers both plus key forms for zoom in", () => { + const zoomInItems = viewSubmenu().filter((item) => item.role === "zoomIn"); + + expect(zoomInItems).toEqual( + expect.arrayContaining([ + expect.objectContaining({ accelerator: "Ctrl+=", role: "zoomIn" }), + expect.objectContaining({ accelerator: "Ctrl+Plus", role: "zoomIn", visible: false }), + ]), + ); + }); + + it("keeps the direct minus accelerator for zoom out", () => { + expect(viewSubmenu()).toContainEqual(expect.objectContaining({ accelerator: "Ctrl+-", role: "zoomOut" })); + }); +}); diff --git a/frontend/src/main/menu.ts b/frontend/src/main/menu.ts new file mode 100644 index 0000000000..fc0fc62d79 --- /dev/null +++ b/frontend/src/main/menu.ts @@ -0,0 +1,36 @@ +import type { MenuItemConstructorOptions } from "electron"; + +export function buildWindowsAppMenuTemplate(): MenuItemConstructorOptions[] { + return [ + { + label: "Edit", + submenu: [ + { role: "undo" }, + { role: "redo" }, + { type: "separator" }, + { role: "cut" }, + { role: "copy" }, + { role: "paste" }, + { role: "selectAll" }, + ], + }, + { + label: "View", + submenu: [ + { role: "reload" }, + { role: "toggleDevTools" }, + { type: "separator" }, + { role: "resetZoom" }, + { accelerator: "Ctrl+=", role: "zoomIn" }, + { accelerator: "Ctrl+Plus", acceleratorWorksWhenHidden: true, role: "zoomIn", visible: false }, + { accelerator: "Ctrl+-", role: "zoomOut" }, + { type: "separator" }, + { role: "togglefullscreen" }, + ], + }, + { + label: "Window", + submenu: [{ role: "minimize" }, { role: "close" }], + }, + ]; +}