diff --git a/apps/desktop/src/renderer/components/layout/AppLayout.test.tsx b/apps/desktop/src/renderer/components/layout/AppLayout.test.tsx
new file mode 100644
index 00000000..df969554
--- /dev/null
+++ b/apps/desktop/src/renderer/components/layout/AppLayout.test.tsx
@@ -0,0 +1,40 @@
+import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { render, screen, act } from '@testing-library/react';
+import { AppLayout } from './AppLayout';
+import { useUIStore } from '@/stores/ui';
+
+vi.mock('./TitleBar', () => ({ TitleBar: () => null }));
+vi.mock('@/routes/settings', () => ({
+ SettingsPage: () =>
,
+}));
+
+describe('AppLayout', () => {
+ beforeEach(() => {
+ useUIStore.setState({ settingsOpen: false });
+ });
+
+ it('keeps children mounted and only shows the settings overlay when open', () => {
+ render(
+
+
home
+
+ );
+
+ expect(screen.getByTestId('home')).toBeInTheDocument();
+ expect(screen.queryByTestId('settings-overlay')).toBeNull();
+
+ act(() => {
+ useUIStore.getState().openSettings();
+ });
+
+ // Home stays mounted underneath the overlay — the session is never torn down.
+ expect(screen.getByTestId('home')).toBeInTheDocument();
+ expect(screen.getByTestId('settings-overlay')).toBeInTheDocument();
+
+ act(() => {
+ useUIStore.getState().closeSettings();
+ });
+ expect(screen.queryByTestId('settings-overlay')).toBeNull();
+ expect(screen.getByTestId('home')).toBeInTheDocument();
+ });
+});
diff --git a/apps/desktop/src/renderer/components/layout/AppLayout.tsx b/apps/desktop/src/renderer/components/layout/AppLayout.tsx
index cb912c00..7bdb9609 100644
--- a/apps/desktop/src/renderer/components/layout/AppLayout.tsx
+++ b/apps/desktop/src/renderer/components/layout/AppLayout.tsx
@@ -1,15 +1,30 @@
import type { ReactNode } from 'react';
import { TitleBar } from './TitleBar';
+import { SettingsPage } from '@/routes/settings';
+import { useUIStore } from '@/stores/ui';
interface AppLayoutProps {
children: ReactNode;
}
export function AppLayout({ children }: AppLayoutProps) {
+ const settingsOpen = useUIStore((s) => s.settingsOpen);
+
return (
- {children}
+
+ {children}
+
+ {/* Settings is an overlay rather than a route so opening it keeps Home
+ (and the active session) mounted underneath. Scoped to the content
+ area so the title bar / window controls stay usable. */}
+ {settingsOpen && (
+