diff --git a/packages/app-core/src/components/TitleBar.tsx b/packages/app-core/src/components/TitleBar.tsx
index 62d58caa..0b32c2e8 100644
--- a/packages/app-core/src/components/TitleBar.tsx
+++ b/packages/app-core/src/components/TitleBar.tsx
@@ -6,6 +6,7 @@ import { isArchiveTabPath } from '@shared/archive'
import { isTrashTabPath } from '@shared/trash'
import { isQuickNotesTabPath } from '@shared/quick-notes'
import { resolveSystemFolderLabels } from '../lib/system-folder-labels'
+import { shouldShowWindowControls } from '../lib/titlebar'
export function TitleBar(): JSX.Element {
const vault = useStore((s) => s.vault)
@@ -14,6 +15,7 @@ export function TitleBar(): JSX.Element {
const systemFolderLabels = useStore((s) => s.systemFolderLabels)
const workspaceMode = useStore((s) => s.workspaceMode)
const isMac = window.zen.platformSync() === 'darwin'
+ const runtime = window.zen.getAppInfo().runtime
const labels = resolveSystemFolderLabels(systemFolderLabels)
const title = activeNote
@@ -47,7 +49,7 @@ export function TitleBar(): JSX.Element {
)}
- {!isMac && (
+ {shouldShowWindowControls(isMac ? 'darwin' : 'other', runtime) && (
window.zen.windowMinimize()} label="–" />
window.zen.windowToggleMaximize()} label="▢" />
diff --git a/packages/app-core/src/lib/titlebar.test.ts b/packages/app-core/src/lib/titlebar.test.ts
new file mode 100644
index 00000000..21938110
--- /dev/null
+++ b/packages/app-core/src/lib/titlebar.test.ts
@@ -0,0 +1,19 @@
+import { describe, expect, it } from 'vitest'
+import { shouldShowWindowControls } from './titlebar'
+
+describe('shouldShowWindowControls — hidden on mac and in the web runtime', () => {
+ it('shows controls on desktop, non-mac', () => {
+ expect(shouldShowWindowControls('win32', 'desktop')).toBe(true)
+ expect(shouldShowWindowControls('linux', 'desktop')).toBe(true)
+ })
+
+ it('hides controls in the web runtime, regardless of platform', () => {
+ expect(shouldShowWindowControls('win32', 'web')).toBe(false)
+ expect(shouldShowWindowControls('linux', 'web')).toBe(false)
+ })
+
+ it('hides controls on mac, regardless of runtime', () => {
+ expect(shouldShowWindowControls('darwin', 'desktop')).toBe(false)
+ expect(shouldShowWindowControls('darwin', 'web')).toBe(false)
+ })
+})
\ No newline at end of file
diff --git a/packages/app-core/src/lib/titlebar.ts b/packages/app-core/src/lib/titlebar.ts
new file mode 100644
index 00000000..59630ddd
--- /dev/null
+++ b/packages/app-core/src/lib/titlebar.ts
@@ -0,0 +1,9 @@
+/**
+ * Whether the native window controls (minimize/maximize/close) should
+ * be shown. They call Electron-only APIs, so they're hidden on mac
+ * (native traffic lights instead) and in the web runtime, where there
+ * is no native window to control.
+ */
+export function shouldShowWindowControls(platform: string, runtime: string): boolean {
+ return platform !== 'darwin' && runtime !== 'web'
+}
\ No newline at end of file