diff --git a/src/renderer/components/layout/AppShell.tsx b/src/renderer/components/layout/AppShell.tsx
index 4805a2b..ef1eab3 100644
--- a/src/renderer/components/layout/AppShell.tsx
+++ b/src/renderer/components/layout/AppShell.tsx
@@ -11,13 +11,43 @@ import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@/componen
import { useFileShortcuts } from '@/hooks/use-file-shortcuts';
import { useRestoreLastFolder } from '@/hooks/use-restore-last-folder';
import { useRegisterMenuCommands, useBridgeNativeMenu } from '@/lib/commands/register-menu-commands';
+import { useZenMode } from '@/hooks/use-zen-mode';
export function AppShell() {
useFileShortcuts();
useRestoreLastFolder();
useRegisterMenuCommands();
useBridgeNativeMenu();
+ useZenMode();
const { sidebarVisible, previewVisible, paneSizes, setPaneSizes } = useAppStore();
+ const zenMode = useAppStore((s) => s.zenMode);
+
+ if (zenMode) {
+ return (
+
+ setPaneSizes({ sidebar: 0, editor: sizes[0], preview: sizes[1] })}
+ >
+
+
+
+ {previewVisible && (
+ <>
+
+
+
+
+ >
+ )}
+
+
+ );
+ }
return (
diff --git a/src/renderer/hooks/use-zen-mode.ts b/src/renderer/hooks/use-zen-mode.ts
new file mode 100644
index 0000000..f3109a6
--- /dev/null
+++ b/src/renderer/hooks/use-zen-mode.ts
@@ -0,0 +1,22 @@
+import { useEffect } from 'react';
+import { useAppStore } from '@/stores/app-store';
+
+/**
+ * Mounts a global keydown listener that exits zen mode when the user
+ * presses Escape. Should be called once at the App root.
+ */
+export function useZenMode() {
+ const zenMode = useAppStore((s) => s.zenMode);
+ const setZenMode = useAppStore((s) => s.setZenMode);
+
+ useEffect(() => {
+ if (!zenMode) return;
+ const handler = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') {
+ setZenMode(false);
+ }
+ };
+ window.addEventListener('keydown', handler);
+ return () => window.removeEventListener('keydown', handler);
+ }, [zenMode, setZenMode]);
+}
diff --git a/tests/unit/hooks/use-zen-mode.test.ts b/tests/unit/hooks/use-zen-mode.test.ts
new file mode 100644
index 0000000..6f97fbe
--- /dev/null
+++ b/tests/unit/hooks/use-zen-mode.test.ts
@@ -0,0 +1,31 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { renderHook } from '@testing-library/react';
+import { useZenMode } from '@/hooks/use-zen-mode';
+import { useAppStore } from '@/stores/app-store';
+
+describe('useZenMode', () => {
+ beforeEach(() => {
+ localStorage.clear();
+ useAppStore.setState({ ...useAppStore.getInitialState(), zenMode: true });
+ });
+
+ it('attaches a keydown listener that exits zen mode on Escape', () => {
+ renderHook(() => useZenMode());
+ expect(useAppStore.getState().zenMode).toBe(true);
+
+ // Simulate Escape keydown
+ const event = new KeyboardEvent('keydown', { key: 'Escape' });
+ window.dispatchEvent(event);
+
+ expect(useAppStore.getState().zenMode).toBe(false);
+ });
+
+ it('does nothing if zen mode is already off', () => {
+ useAppStore.setState({ ...useAppStore.getInitialState(), zenMode: false });
+ const setZenMode = vi.fn();
+ useAppStore.setState({ setZenMode });
+ renderHook(() => useZenMode());
+ // No Escape dispatched; setZenMode should not be called
+ expect(setZenMode).not.toHaveBeenCalled();
+ });
+});