feat(renderer): AppHeader with sidebar/preview toggles + theme toggle

This commit is contained in:
2026-06-05 11:40:54 +05:30
parent c715bb354c
commit 7fbbd60525
3 changed files with 91 additions and 0 deletions
@@ -0,0 +1,41 @@
import { PanelLeft, PanelRight } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { ThemeToggle } from '@/components/theme-toggle';
import { useAppStore } from '@/stores/app-store';
export function AppHeader() {
const { sidebarVisible, previewVisible, toggleSidebar, togglePreview } = useAppStore();
return (
<header className="flex h-14 items-center justify-between border-b border-border bg-card/40 px-4 backdrop-blur">
<div className="flex items-center gap-3">
<div
className="h-7 w-7 rounded-md bg-gradient-to-br from-brand to-brand-dark shadow-[var(--shadow-glow-brand)]"
aria-label="MarkdownConverter logo"
/>
<h1 className="font-display text-lg font-bold tracking-tight">MarkdownConverter</h1>
</div>
<div className="flex items-center gap-1">
<Button
variant="ghost"
size="icon"
aria-label="Toggle sidebar"
aria-pressed={sidebarVisible}
onClick={toggleSidebar}
>
<PanelLeft className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
aria-label="Toggle preview"
aria-pressed={previewVisible}
onClick={togglePreview}
>
<PanelRight className="h-4 w-4" />
</Button>
<ThemeToggle />
</div>
</header>
);
}
+17
View File
@@ -10,3 +10,20 @@ declare global {
if (typeof window !== 'undefined' && !window.electronAPI) {
window.electronAPI = {};
}
// Mock matchMedia for next-themes (jsdom doesn't have it)
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query: string) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => true,
}),
});
}
+33
View File
@@ -0,0 +1,33 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ThemeProvider } from '@/components/theme-provider';
import { AppHeader } from '@/components/layout/AppHeader';
import { useAppStore } from '@/stores/app-store';
describe('AppHeader', () => {
beforeEach(() => {
localStorage.clear();
useAppStore.setState({ sidebarVisible: true, previewVisible: true, zenMode: false });
});
it('renders the app title', () => {
render(
<ThemeProvider defaultTheme="dark" attribute="class">
<AppHeader />
</ThemeProvider>
);
expect(screen.getByText(/markdownconverter/i)).toBeInTheDocument();
});
it('toggles sidebar when sidebar button clicked', async () => {
render(
<ThemeProvider defaultTheme="dark" attribute="class">
<AppHeader />
</ThemeProvider>
);
const btn = screen.getByRole('button', { name: /toggle sidebar/i });
await userEvent.click(btn);
expect(useAppStore.getState().sidebarVisible).toBe(false);
});
});