From 03dac3811677eea230a2b6157d43402d5394c2a8 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Fri, 3 Jul 2026 16:00:29 -0400 Subject: [PATCH 1/2] feat(zoom): add zoom control commands to command menu Generated-By: PostHog Code --- apps/code/src/main/menu.ts | 4 +- .../platform-adapters/electron-main-window.ts | 13 +++++ packages/host-router/src/routers/os.router.ts | 16 +++++++ packages/platform/src/main-window.ts | 3 ++ packages/shared/src/analytics-events.ts | 5 +- .../ui/src/features/command/CommandMenu.tsx | 47 +++++++++++++++++++ .../features/command/keyboard-shortcuts.ts | 5 ++ 7 files changed, 90 insertions(+), 3 deletions(-) diff --git a/apps/code/src/main/menu.ts b/apps/code/src/main/menu.ts index ca79b8dfa8..e6b8f133fa 100644 --- a/apps/code/src/main/menu.ts +++ b/apps/code/src/main/menu.ts @@ -25,14 +25,14 @@ import { saveZoomLevel } from "./utils/store"; // Zoom is measured in Electron "levels" (factor = 1.2 ** level; 0 = 100%). // ZOOM_STEP is one Zoom In/Out notch; the bounds clamp the level so a runaway // accelerator can't persist an unusable zoom across restarts. -const ZOOM_STEP = 0.5; +export const ZOOM_STEP = 0.5; const ZOOM_MIN = -3; const ZOOM_MAX = 3; // Apply a zoom change to the focused window and persist the new level so it // survives restarts. `delta` adjusts relative to the current level; "reset" // returns to 100%. -function applyZoom(delta: number | "reset"): void { +export function applyZoom(delta: number | "reset"): void { const webContents = BrowserWindow.getFocusedWindow()?.webContents; if (!webContents) return; const next = delta === "reset" ? 0 : webContents.getZoomLevel() + delta; diff --git a/apps/code/src/main/platform-adapters/electron-main-window.ts b/apps/code/src/main/platform-adapters/electron-main-window.ts index abdc6b2771..2a758f0d51 100644 --- a/apps/code/src/main/platform-adapters/electron-main-window.ts +++ b/apps/code/src/main/platform-adapters/electron-main-window.ts @@ -1,6 +1,7 @@ import type { IMainWindow } from "@posthog/platform/main-window"; import { app, type BrowserWindow } from "electron"; import { injectable } from "inversify"; +import { applyZoom, ZOOM_STEP } from "../menu"; @injectable() export class ElectronMainWindow implements IMainWindow { @@ -35,4 +36,16 @@ export class ElectronMainWindow implements IMainWindow { app.on("browser-window-focus", listener); return () => app.off("browser-window-focus", listener); } + + public zoomIn(): void { + applyZoom(ZOOM_STEP); + } + + public zoomOut(): void { + applyZoom(-ZOOM_STEP); + } + + public resetZoom(): void { + applyZoom("reset"); + } } diff --git a/packages/host-router/src/routers/os.router.ts b/packages/host-router/src/routers/os.router.ts index 77cd41f094..364e972fbd 100644 --- a/packages/host-router/src/routers/os.router.ts +++ b/packages/host-router/src/routers/os.router.ts @@ -1,4 +1,8 @@ import { publicProcedure, router } from "@posthog/host-trpc/trpc"; +import { + type IMainWindow, + MAIN_WINDOW_SERVICE, +} from "@posthog/platform/main-window"; import { OS_SERVICE } from "@posthog/workspace-server/services/os/identifiers"; import type { OsService } from "@posthog/workspace-server/services/os/os"; import { @@ -120,4 +124,16 @@ export const osRouter = router({ .get(OS_SERVICE) .saveClipboardFile(input.base64Data, input.originalName), ), + + zoomIn: publicProcedure.mutation(({ ctx }) => + ctx.container.get(MAIN_WINDOW_SERVICE).zoomIn(), + ), + + zoomOut: publicProcedure.mutation(({ ctx }) => + ctx.container.get(MAIN_WINDOW_SERVICE).zoomOut(), + ), + + resetZoom: publicProcedure.mutation(({ ctx }) => + ctx.container.get(MAIN_WINDOW_SERVICE).resetZoom(), + ), }); diff --git a/packages/platform/src/main-window.ts b/packages/platform/src/main-window.ts index e5f6f9cbfc..01ae74d9ae 100644 --- a/packages/platform/src/main-window.ts +++ b/packages/platform/src/main-window.ts @@ -4,6 +4,9 @@ export interface IMainWindow { isMinimized(): boolean; restore(): void; onFocus(handler: () => void): () => void; + zoomIn(): void; + zoomOut(): void; + resetZoom(): void; } export const MAIN_WINDOW_SERVICE = Symbol.for("posthog.platform.mainWindow"); diff --git a/packages/shared/src/analytics-events.ts b/packages/shared/src/analytics-events.ts index 1e90db211d..e692c2f1ae 100644 --- a/packages/shared/src/analytics-events.ts +++ b/packages/shared/src/analytics-events.ts @@ -56,7 +56,10 @@ export type CommandMenuAction = | "search-files" | "open-file" | "reload-window" - | "show-log-folder"; + | "show-log-folder" + | "zoom-in" + | "zoom-out" + | "zoom-reset"; // Event property interfaces export interface TaskListViewProperties { diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index b7419edc0a..662d614b8c 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -4,6 +4,11 @@ import { EnvelopeSimple, HashIcon, } from "@phosphor-icons/react"; +import { resolveService } from "@posthog/di/container"; +import { + HOST_TRPC_CLIENT, + type HostTrpcClient, +} from "@posthog/host-router/client"; import { Autocomplete, AutocompleteCollection, @@ -66,6 +71,8 @@ import { ReloadIcon, SunIcon, ViewVerticalIcon, + ZoomInIcon, + ZoomOutIcon, } from "@radix-ui/react-icons"; import { useCallback, useEffect, useMemo, useState } from "react"; @@ -350,9 +357,49 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { }, ]; + const view: Command[] = [ + { + id: "zoom-in", + label: "Zoom in", + keywords: "zoom increase larger", + icon: , + action: "zoom-in", + shortcut: SHORTCUTS.ZOOM_IN, + onRun: () => + void resolveService( + HOST_TRPC_CLIENT, + ).os.zoomIn.mutate(), + }, + { + id: "zoom-out", + label: "Zoom out", + keywords: "zoom decrease smaller", + icon: , + action: "zoom-out", + shortcut: SHORTCUTS.ZOOM_OUT, + onRun: () => + void resolveService( + HOST_TRPC_CLIENT, + ).os.zoomOut.mutate(), + }, + { + id: "zoom-reset", + label: "Reset zoom", + keywords: "zoom actual size default", + icon: , + action: "zoom-reset", + shortcut: SHORTCUTS.RESET_ZOOM, + onRun: () => + void resolveService( + HOST_TRPC_CLIENT, + ).os.resetZoom.mutate(), + }, + ]; + const out: CommandSection[] = [ { label: "Actions", items: actions }, { label: "Navigation", items: navigation }, + { label: "View", items: view }, { label: "Developer", items: developer }, ]; diff --git a/packages/ui/src/features/command/keyboard-shortcuts.ts b/packages/ui/src/features/command/keyboard-shortcuts.ts index 246ad5ae72..c15594d3a7 100644 --- a/packages/ui/src/features/command/keyboard-shortcuts.ts +++ b/packages/ui/src/features/command/keyboard-shortcuts.ts @@ -30,6 +30,9 @@ export const SHORTCUTS = { SUBMIT_BLUR: "mod+enter", SWITCH_MESSAGING_MODE: "mod+s", RELOAD_WINDOW: "mod+shift+r", + ZOOM_IN: "mod+=", + ZOOM_OUT: "mod+-", + RESET_ZOOM: "mod+0", } as const; export type ShortcutCategory = "general" | "navigation" | "panels" | "editor"; @@ -264,6 +267,8 @@ function formatKey(key: string): string { if (k === ",") return ","; if (k === "[") return "["; if (k === "]") return "]"; + if (k === "=") return "+"; + if (k === "-") return "-"; if (k === "tab") return "Tab"; return k.toUpperCase(); } From b28a862d3cc5c6c74f01c72c9cb70126b9f123a6 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Mon, 6 Jul 2026 09:08:57 -0400 Subject: [PATCH 2/2] fix(zoom): address review comments Rename shadowed view variable to viewCommands and list zoom shortcuts in the keyboard shortcuts sheet. Generated-By: PostHog Code Task-Id: 4f8606e0-f8d6-43e2-86ff-eef4c210e006 --- .../ui/src/features/command/CommandMenu.tsx | 4 ++-- .../src/features/command/keyboard-shortcuts.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/features/command/CommandMenu.tsx b/packages/ui/src/features/command/CommandMenu.tsx index 662d614b8c..f20e663591 100644 --- a/packages/ui/src/features/command/CommandMenu.tsx +++ b/packages/ui/src/features/command/CommandMenu.tsx @@ -357,7 +357,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { }, ]; - const view: Command[] = [ + const viewCommands: Command[] = [ { id: "zoom-in", label: "Zoom in", @@ -399,7 +399,7 @@ export function CommandMenu({ open, onOpenChange }: CommandMenuProps) { const out: CommandSection[] = [ { label: "Actions", items: actions }, { label: "Navigation", items: navigation }, - { label: "View", items: view }, + { label: "View", items: viewCommands }, { label: "Developer", items: developer }, ]; diff --git a/packages/ui/src/features/command/keyboard-shortcuts.ts b/packages/ui/src/features/command/keyboard-shortcuts.ts index c15594d3a7..94279b6490 100644 --- a/packages/ui/src/features/command/keyboard-shortcuts.ts +++ b/packages/ui/src/features/command/keyboard-shortcuts.ts @@ -72,6 +72,24 @@ export const KEYBOARD_SHORTCUTS: KeyboardShortcut[] = [ description: "Show keyboard shortcuts", category: "general", }, + { + id: "zoom-in", + keys: SHORTCUTS.ZOOM_IN, + description: "Zoom in", + category: "general", + }, + { + id: "zoom-out", + keys: SHORTCUTS.ZOOM_OUT, + description: "Zoom out", + category: "general", + }, + { + id: "reset-zoom", + keys: SHORTCUTS.RESET_ZOOM, + description: "Reset zoom", + category: "general", + }, { id: "switch-messaging-mode", keys: SHORTCUTS.SWITCH_MESSAGING_MODE,