mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
feat(renderer): AppHeader wired to command store
- toggle sidebar/preview buttons dispatch through command store - new 'shortcuts.show' command (Keyboard icon, opens shortcuts panel later) - AppHeader.test.tsx updated: registers matching commands in beforeEach - integration test fixed: 'Open folder' button now matches 2 (toolbar + sidebar) - 155/155 tests pass
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
import { PanelLeft, PanelRight } from 'lucide-react';
|
import { PanelLeft, PanelRight, Keyboard } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ThemeToggle } from '@/components/theme-toggle';
|
import { ThemeToggle } from '@/components/theme-toggle';
|
||||||
import { useAppStore } from '@/stores/app-store';
|
import { useAppStore } from '@/stores/app-store';
|
||||||
|
import { useCommandStore } from '@/stores/command-store';
|
||||||
|
|
||||||
export function AppHeader() {
|
export function AppHeader() {
|
||||||
const { sidebarVisible, previewVisible, toggleSidebar, togglePreview } = useAppStore();
|
const { sidebarVisible, previewVisible } = useAppStore();
|
||||||
|
const dispatch = useCommandStore((s) => s.dispatch);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="flex h-14 items-center justify-between border-b border-border bg-card/40 px-4 backdrop-blur">
|
<header className="flex h-14 items-center justify-between border-b border-border bg-card/40 px-4 backdrop-blur">
|
||||||
@@ -21,7 +23,8 @@ export function AppHeader() {
|
|||||||
size="icon"
|
size="icon"
|
||||||
aria-label="Toggle sidebar"
|
aria-label="Toggle sidebar"
|
||||||
aria-pressed={sidebarVisible}
|
aria-pressed={sidebarVisible}
|
||||||
onClick={toggleSidebar}
|
data-testid="header-toggle-sidebar"
|
||||||
|
onClick={() => dispatch('view.toggleSidebar')}
|
||||||
>
|
>
|
||||||
<PanelLeft className="h-4 w-4" />
|
<PanelLeft className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -30,10 +33,20 @@ export function AppHeader() {
|
|||||||
size="icon"
|
size="icon"
|
||||||
aria-label="Toggle preview"
|
aria-label="Toggle preview"
|
||||||
aria-pressed={previewVisible}
|
aria-pressed={previewVisible}
|
||||||
onClick={togglePreview}
|
data-testid="header-toggle-preview"
|
||||||
|
onClick={() => dispatch('view.togglePreview')}
|
||||||
>
|
>
|
||||||
<PanelRight className="h-4 w-4" />
|
<PanelRight className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
aria-label="Keyboard shortcuts"
|
||||||
|
data-testid="header-shortcuts"
|
||||||
|
onClick={() => dispatch('shortcuts.show')}
|
||||||
|
>
|
||||||
|
<Keyboard className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -4,11 +4,21 @@ import userEvent from '@testing-library/user-event';
|
|||||||
import { ThemeProvider } from '@/components/theme-provider';
|
import { ThemeProvider } from '@/components/theme-provider';
|
||||||
import { AppHeader } from '@/components/layout/AppHeader';
|
import { AppHeader } from '@/components/layout/AppHeader';
|
||||||
import { useAppStore } from '@/stores/app-store';
|
import { useAppStore } from '@/stores/app-store';
|
||||||
|
import { useCommandStore } from '@/stores/command-store';
|
||||||
|
|
||||||
describe('AppHeader', () => {
|
describe('AppHeader', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
useAppStore.setState({ sidebarVisible: true, previewVisible: true, zenMode: false });
|
useAppStore.setState({ sidebarVisible: true, previewVisible: true, zenMode: false });
|
||||||
|
useCommandStore.setState({ handlers: {} });
|
||||||
|
// Mirror what AppShell registers so dispatching actually does something.
|
||||||
|
useCommandStore.getState().register('view.toggleSidebar', () => {
|
||||||
|
useAppStore.getState().toggleSidebar();
|
||||||
|
});
|
||||||
|
useCommandStore.getState().register('view.togglePreview', () => {
|
||||||
|
useAppStore.getState().togglePreview();
|
||||||
|
});
|
||||||
|
useCommandStore.getState().register('shortcuts.show', () => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the app title', () => {
|
it('renders the app title', () => {
|
||||||
@@ -30,4 +40,28 @@ describe('AppHeader', () => {
|
|||||||
await userEvent.click(btn);
|
await userEvent.click(btn);
|
||||||
expect(useAppStore.getState().sidebarVisible).toBe(false);
|
expect(useAppStore.getState().sidebarVisible).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('toggles preview when preview button clicked', async () => {
|
||||||
|
render(
|
||||||
|
<ThemeProvider defaultTheme="dark" attribute="class">
|
||||||
|
<AppHeader />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
const btn = screen.getByRole('button', { name: /toggle preview/i });
|
||||||
|
await userEvent.click(btn);
|
||||||
|
expect(useAppStore.getState().previewVisible).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables-shortcut button dispatches shortcuts.show', async () => {
|
||||||
|
render(
|
||||||
|
<ThemeProvider defaultTheme="dark" attribute="class">
|
||||||
|
<AppHeader />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
const btn = screen.getByTestId('header-shortcuts');
|
||||||
|
await userEvent.click(btn);
|
||||||
|
// No observable side effect; the command was registered as a no-op.
|
||||||
|
// The test passes if no error is thrown and the click is processed.
|
||||||
|
expect(btn).toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -71,9 +71,11 @@ describe('Phase 5 integration', () => {
|
|||||||
|
|
||||||
it('opening a folder via the Open Folder button populates the tree', async () => {
|
it('opening a folder via the Open Folder button populates the tree', async () => {
|
||||||
render(<AppShell />);
|
render(<AppShell />);
|
||||||
const openBtn = screen.getByRole('button', { name: /open folder/i });
|
// Two buttons share the "Open folder" name (toolbar + sidebar).
|
||||||
|
// Either one triggers the same command, so click the first match.
|
||||||
|
const buttons = screen.getAllByRole('button', { name: /open folder/i });
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
fireEvent.click(openBtn);
|
fireEvent.click(buttons[0]);
|
||||||
});
|
});
|
||||||
// After openFolder, the tree should have children
|
// After openFolder, the tree should have children
|
||||||
const state = useFileStore.getState();
|
const state = useFileStore.getState();
|
||||||
|
|||||||
Reference in New Issue
Block a user