mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
feat(renderer): register 9 modal-opening commands in command store
This commit is contained in:
@@ -12,41 +12,79 @@ import { useMenuAction } from '@/hooks/use-menu-action';
|
|||||||
* Phase 7+ will add the dialog-driven commands (export, settings, etc.)
|
* Phase 7+ will add the dialog-driven commands (export, settings, etc.)
|
||||||
* once the corresponding modals exist.
|
* once the corresponding modals exist.
|
||||||
*/
|
*/
|
||||||
|
export function registerMenuCommands(): void {
|
||||||
|
const { registerMany } = useCommandStore.getState();
|
||||||
|
|
||||||
|
registerMany({
|
||||||
|
'settings.open': () => useAppStore.getState().openModal('settings'),
|
||||||
|
'help.about': () => useAppStore.getState().openModal('about'),
|
||||||
|
'help.welcome': () => useAppStore.getState().openModal('welcome'),
|
||||||
|
'file.exportPdf': () => {
|
||||||
|
const activeTabId = useFileStore.getState().activeTabId;
|
||||||
|
if (!activeTabId) return;
|
||||||
|
useAppStore.getState().openModal('export-pdf', { sourcePath: activeTabId });
|
||||||
|
},
|
||||||
|
'file.exportDocx': () => {
|
||||||
|
const activeTabId = useFileStore.getState().activeTabId;
|
||||||
|
if (!activeTabId) return;
|
||||||
|
useAppStore.getState().openModal('export-docx', { sourcePath: activeTabId });
|
||||||
|
},
|
||||||
|
'file.exportHtml': () => {
|
||||||
|
const activeTabId = useFileStore.getState().activeTabId;
|
||||||
|
if (!activeTabId) return;
|
||||||
|
useAppStore.getState().openModal('export-html', { sourcePath: activeTabId });
|
||||||
|
},
|
||||||
|
'file.exportBatch': () => {
|
||||||
|
const paths = useFileStore.getState().openTabs.map((t) => t.path);
|
||||||
|
if (paths.length === 0) return;
|
||||||
|
useAppStore.getState().openModal('export-batch', { sourcePaths: paths });
|
||||||
|
},
|
||||||
|
'file.confirmClose': () => {
|
||||||
|
/* stub — wired in later phase */
|
||||||
|
},
|
||||||
|
'app.quit': () => {
|
||||||
|
/* stub — wired in later phase */
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { register } = useCommandStore.getState();
|
||||||
|
register('file.open', () => {
|
||||||
|
void useFileStore.getState().openFileDialog();
|
||||||
|
});
|
||||||
|
register('file.openFolder', () => {
|
||||||
|
void useFileStore.getState().openFolderDialog();
|
||||||
|
});
|
||||||
|
register('file.save', () => {
|
||||||
|
void useFileStore.getState().saveActiveBuffer();
|
||||||
|
});
|
||||||
|
register('file.closeTab', () => {
|
||||||
|
const { activeTabId, closeTab } = useFileStore.getState();
|
||||||
|
if (activeTabId) closeTab(activeTabId);
|
||||||
|
});
|
||||||
|
register('tab.next', () => {
|
||||||
|
const { openTabs, activeTabId, setActiveTab } = useFileStore.getState();
|
||||||
|
if (openTabs.length === 0) return;
|
||||||
|
const idx = activeTabId ? openTabs.findIndex((t) => t.id === activeTabId) : 0;
|
||||||
|
const safeIdx = idx === -1 ? 0 : idx;
|
||||||
|
const nextIdx = safeIdx >= openTabs.length - 1 ? 0 : safeIdx + 1;
|
||||||
|
setActiveTab(openTabs[nextIdx].id);
|
||||||
|
});
|
||||||
|
register('tab.prev', () => {
|
||||||
|
const { openTabs, activeTabId, setActiveTab } = useFileStore.getState();
|
||||||
|
if (openTabs.length === 0) return;
|
||||||
|
const idx = activeTabId ? openTabs.findIndex((t) => t.id === activeTabId) : 0;
|
||||||
|
const safeIdx = idx === -1 ? 0 : idx;
|
||||||
|
const nextIdx = safeIdx <= 0 ? openTabs.length - 1 : safeIdx - 1;
|
||||||
|
setActiveTab(openTabs[nextIdx].id);
|
||||||
|
});
|
||||||
|
register('view.toggleSidebar', () => useAppStore.getState().toggleSidebar());
|
||||||
|
register('view.togglePreview', () => useAppStore.getState().togglePreview());
|
||||||
|
}
|
||||||
|
|
||||||
export function useRegisterMenuCommands(): void {
|
export function useRegisterMenuCommands(): void {
|
||||||
// Register handlers in the command store.
|
// Register handlers in the command store.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { register } = useCommandStore.getState();
|
registerMenuCommands();
|
||||||
register('file.open', () => {
|
|
||||||
void useFileStore.getState().openFileDialog();
|
|
||||||
});
|
|
||||||
register('file.openFolder', () => {
|
|
||||||
void useFileStore.getState().openFolderDialog();
|
|
||||||
});
|
|
||||||
register('file.save', () => {
|
|
||||||
void useFileStore.getState().saveActiveBuffer();
|
|
||||||
});
|
|
||||||
register('file.closeTab', () => {
|
|
||||||
const { activeTabId, closeTab } = useFileStore.getState();
|
|
||||||
if (activeTabId) closeTab(activeTabId);
|
|
||||||
});
|
|
||||||
register('tab.next', () => {
|
|
||||||
const { openTabs, activeTabId, setActiveTab } = useFileStore.getState();
|
|
||||||
if (openTabs.length === 0) return;
|
|
||||||
const idx = activeTabId ? openTabs.findIndex((t) => t.id === activeTabId) : 0;
|
|
||||||
const safeIdx = idx === -1 ? 0 : idx;
|
|
||||||
const nextIdx = safeIdx >= openTabs.length - 1 ? 0 : safeIdx + 1;
|
|
||||||
setActiveTab(openTabs[nextIdx].id);
|
|
||||||
});
|
|
||||||
register('tab.prev', () => {
|
|
||||||
const { openTabs, activeTabId, setActiveTab } = useFileStore.getState();
|
|
||||||
if (openTabs.length === 0) return;
|
|
||||||
const idx = activeTabId ? openTabs.findIndex((t) => t.id === activeTabId) : 0;
|
|
||||||
const safeIdx = idx === -1 ? 0 : idx;
|
|
||||||
const nextIdx = safeIdx <= 0 ? openTabs.length - 1 : safeIdx - 1;
|
|
||||||
setActiveTab(openTabs[nextIdx].id);
|
|
||||||
});
|
|
||||||
register('view.toggleSidebar', () => useAppStore.getState().toggleSidebar());
|
|
||||||
register('view.togglePreview', () => useAppStore.getState().togglePreview());
|
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||||
|
import { registerMenuCommands } from '@/lib/commands/register-menu-commands';
|
||||||
|
import { useCommandStore } from '@/stores/command-store';
|
||||||
|
import { useAppStore } from '@/stores/app-store';
|
||||||
|
import { useFileStore } from '@/stores/file-store';
|
||||||
|
import { useEditorStore } from '@/stores/editor-store';
|
||||||
|
|
||||||
|
describe('modal commands', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
localStorage.clear();
|
||||||
|
useCommandStore.setState({ handlers: {}, userBindings: {} } as any);
|
||||||
|
useAppStore.setState({ modal: { kind: null } } as any);
|
||||||
|
useFileStore.setState({ activeTabId: '/x.md', openTabs: [{ id: '/x.md', path: '/x.md', title: 'x.md', dirty: false }] } as any);
|
||||||
|
useEditorStore.setState({ buffers: new Map([['/x.md', { id: '/x.md', path: '/x.md', content: '# hi', dirty: false }]]) } as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('settings.open opens settings modal', () => {
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('settings.open');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'settings' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('help.about opens about modal', () => {
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('help.about');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'about' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('help.welcome opens welcome modal', () => {
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('help.welcome');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'welcome' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('file.exportPdf opens export-pdf modal with active path', () => {
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('file.exportPdf');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'export-pdf', props: { sourcePath: '/x.md' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('file.exportDocx opens export-docx modal', () => {
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('file.exportDocx');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'export-docx', props: { sourcePath: '/x.md' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('file.exportBatch opens export-batch modal with all open files', () => {
|
||||||
|
useFileStore.setState({ activeTabId: '/x.md', openTabs: [{ id: '/x.md', path: '/x.md', title: 'x.md', dirty: false }, { id: '/y.md', path: '/y.md', title: 'y.md', dirty: false }] } as any);
|
||||||
|
registerMenuCommands();
|
||||||
|
useCommandStore.getState().dispatch('file.exportBatch');
|
||||||
|
expect(useAppStore.getState().modal).toEqual({ kind: 'export-batch', props: { sourcePaths: ['/x.md', '/y.md'] } });
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user