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

This commit is contained in:
Brendan Allan
2026-02-02 15:54:25 +08:00
committed by GitHub
parent 141fdef588
commit c02dd067b2
4 changed files with 33 additions and 18 deletions

View File

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

View File

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

View File

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

View File

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