Browse Source

fix(desktop): keep mac titlebar stable under zoom (#11747)

Brendan Allan 3 weeks ago
parent
commit
c02dd067b2

+ 4 - 1
packages/app/src/components/titlebar.tsx

@@ -24,6 +24,8 @@ export function Titlebar() {
   const mac = createMemo(() => platform.platform === "desktop" && platform.os === "macos")
   const windows = createMemo(() => platform.platform === "desktop" && platform.os === "windows")
   const web = createMemo(() => platform.platform === "web")
+  const zoom = () => platform.webviewZoom?.() ?? 1
+  const minHeight = () => (mac() ? `${40 / zoom()}px` : undefined)
 
   const [history, setHistory] = createStore({
     stack: [] as string[],
@@ -134,6 +136,7 @@ export function Titlebar() {
   return (
     <header
       class="h-10 shrink-0 bg-background-base relative grid grid-cols-[auto_minmax(0,1fr)_auto] items-center"
+      style={{ "min-height": minHeight() }}
       data-tauri-drag-region
     >
       <div
@@ -145,7 +148,7 @@ export function Titlebar() {
         data-tauri-drag-region
       >
         <Show when={mac()}>
-          <div class="w-[72px] h-full shrink-0" data-tauri-drag-region />
+          <div class="h-full shrink-0" style={{ width: `${72 / zoom()}px` }} data-tauri-drag-region />
           <div class="xl:hidden w-10 shrink-0 flex items-center justify-center">
             <IconButton
               icon="menu"

+ 4 - 0
packages/app/src/context/platform.tsx

@@ -1,5 +1,6 @@
 import { createSimpleContext } from "@opencode-ai/ui/context"
 import { AsyncStorage, SyncStorage } from "@solid-primitives/storage"
+import type { Accessor } from "solid-js"
 
 export type Platform = {
   /** Platform discriminator */
@@ -55,6 +56,9 @@ export type Platform = {
 
   /** Parse markdown to HTML using native parser (desktop only, returns unprocessed code blocks) */
   parseMarkdown?(markdown: string): Promise<string>
+
+  /** Webview zoom level (desktop only) */
+  webviewZoom?: Accessor<number>
 }
 
 export const { use: usePlatform, provider: PlatformProvider } = createSimpleContext({

+ 3 - 1
packages/desktop/src/index.tsx

@@ -1,5 +1,5 @@
 // @refresh reload
-import "./webview-zoom"
+import { webviewZoom } from "./webview-zoom"
 import { render } from "solid-js/web"
 import { AppBaseProviders, AppInterface, PlatformProvider, Platform } from "@opencode-ai/app"
 import { open, save } from "@tauri-apps/plugin-dialog"
@@ -346,6 +346,8 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
   parseMarkdown: async (markdown: string) => {
     return invoke<string>("parse_markdown_command", { markdown })
   },
+
+  webviewZoom,
 })
 
 createMenu()

+ 22 - 16
packages/desktop/src/webview-zoom.ts

@@ -4,28 +4,34 @@
 
 import { invoke } from "@tauri-apps/api/core"
 import { type as ostype } from "@tauri-apps/plugin-os"
+import { createSignal } from "solid-js"
 
 const OS_NAME = ostype()
 
-let zoomLevel = 1
+const [webviewZoom, setWebviewZoom] = createSignal(1)
 
 const MAX_ZOOM_LEVEL = 10
 const MIN_ZOOM_LEVEL = 0.2
 
+const clamp = (value: number) => Math.min(Math.max(value, MIN_ZOOM_LEVEL), MAX_ZOOM_LEVEL)
+
+const applyZoom = (next: number) => {
+  setWebviewZoom(next)
+  invoke("plugin:webview|set_webview_zoom", {
+    value: next,
+  })
+}
+
 window.addEventListener("keydown", (event) => {
-  if (OS_NAME === "macos" ? event.metaKey : event.ctrlKey) {
-    if (event.key === "-") {
-      zoomLevel -= 0.2
-    } else if (event.key === "=" || event.key === "+") {
-      zoomLevel += 0.2
-    } else if (event.key === "0") {
-      zoomLevel = 1
-    } else {
-      return
-    }
-    zoomLevel = Math.min(Math.max(zoomLevel, MIN_ZOOM_LEVEL), MAX_ZOOM_LEVEL)
-    invoke("plugin:webview|set_webview_zoom", {
-      value: zoomLevel,
-    })
-  }
+  if (!(OS_NAME === "macos" ? event.metaKey : event.ctrlKey)) return
+
+  let newZoom = webviewZoom()
+
+  if (event.key === "-") newZoom -= 0.2
+  if (event.key === "=" || event.key === "+") newZoom += 0.2
+  if (event.key === "0") newZoom = 1
+
+  applyZoom(clamp(newZoom))
 })
+
+export { webviewZoom }