/** * Keyboard Shortcuts Registry and Utilities * Central configuration for all keyboard shortcuts in the application */ // Platform detection export const isMac = typeof navigator !== 'undefined' && /Mac|iPod|iPhone|iPad/.test(navigator.platform); /** * Modifier key display based on platform */ export const modifierKey = isMac ? '⌘' : 'Ctrl'; export const altKey = isMac ? '⌥' : 'Alt'; export const shiftKey = '⇧'; /** * Shortcut definition */ export interface ShortcutDefinition { id: string; keys: string; // react-hotkeys-hook format: 'mod+k', 'mod+shift+n' label: string; // Danish display name description?: string; category: ShortcutCategory; scope?: ShortcutScope; } export type ShortcutCategory = | 'global' | 'navigation' | 'bogforing' | 'faktura' | 'bank' | 'kunder' | 'produkter'; export type ShortcutScope = | 'global' // Works everywhere | 'page' // Only on specific page | 'modal' // Only in modals | 'table'; // Only when table is focused /** * All keyboard shortcuts in the application */ export const shortcuts: Record = { // Global shortcuts openCommandPalette: { id: 'openCommandPalette', keys: 'mod+k', label: 'Kommandopalette', description: 'Hurtig navigation og actions', category: 'global', scope: 'global', }, showShortcuts: { id: 'showShortcuts', keys: 'mod+/', label: 'Vis genveje', description: 'Vis alle tastaturgenveje', category: 'global', scope: 'global', }, closeModal: { id: 'closeModal', keys: 'escape', label: 'Luk', description: 'Luk aktiv modal eller palette', category: 'global', scope: 'global', }, // Navigation shortcuts (G then X pattern) goToDashboard: { id: 'goToDashboard', keys: 'g d', label: 'Dashboard', category: 'navigation', scope: 'global', }, goToKassekladde: { id: 'goToKassekladde', keys: 'g k', label: 'Kassekladde', category: 'navigation', scope: 'global', }, goToKontooversigt: { id: 'goToKontooversigt', keys: 'g o', label: 'Kontooversigt', category: 'navigation', scope: 'global', }, goToFakturaer: { id: 'goToFakturaer', keys: 'g f', label: 'Fakturaer', category: 'navigation', scope: 'global', }, goToKreditnotaer: { id: 'goToKreditnotaer', keys: 'g c', label: 'Kreditnotaer', category: 'navigation', scope: 'global', }, goToBankafstemning: { id: 'goToBankafstemning', keys: 'g b', label: 'Bankafstemning', category: 'navigation', scope: 'global', }, goToKunder: { id: 'goToKunder', keys: 'g u', label: 'Kunder', category: 'navigation', scope: 'global', }, goToProdukter: { id: 'goToProdukter', keys: 'g p', label: 'Produkter', category: 'navigation', scope: 'global', }, goToMomsindberetning: { id: 'goToMomsindberetning', keys: 'g m', label: 'Momsindberetning', category: 'navigation', scope: 'global', }, goToIndstillinger: { id: 'goToIndstillinger', keys: 'g i', label: 'Indstillinger', category: 'navigation', scope: 'global', }, // Bogforing shortcuts (Kassekladde) newDraft: { id: 'newDraft', keys: 'mod+n', label: 'Ny kassekladde', category: 'bogforing', scope: 'page', }, postDraft: { id: 'postDraft', keys: 'mod+enter', label: 'Bogfør kladde', category: 'bogforing', scope: 'page', }, addLine: { id: 'addLine', keys: 'mod+shift+l', label: 'Tilføj linje', category: 'bogforing', scope: 'page', }, saveDraft: { id: 'saveDraft', keys: 'mod+s', label: 'Gem kladde', category: 'bogforing', scope: 'page', }, discardDraft: { id: 'discardDraft', keys: 'mod+backspace', label: 'Kasser kladde', category: 'bogforing', scope: 'page', }, syncBank: { id: 'syncBank', keys: 'mod+r', label: 'Synkroniser bank', description: 'Hent nye transaktioner fra bank', category: 'bank', scope: 'page', }, // Faktura shortcuts newInvoice: { id: 'newInvoice', keys: 'mod+i', label: 'Ny faktura', category: 'faktura', scope: 'page', }, newCreditNote: { id: 'newCreditNote', keys: 'mod+shift+i', label: 'Ny kreditnota', category: 'faktura', scope: 'page', }, newCustomer: { id: 'newCustomer', keys: 'mod+shift+k', label: 'Ny kunde', category: 'kunder', scope: 'page', }, newProduct: { id: 'newProduct', keys: 'mod+shift+p', label: 'Nyt produkt', category: 'produkter', scope: 'page', }, // Bank shortcuts matchTransaction: { id: 'matchTransaction', keys: 'mod+m', label: 'Match transaktion', category: 'bank', scope: 'page', }, }; /** * Get shortcuts by category */ export function getShortcutsByCategory(category: ShortcutCategory): ShortcutDefinition[] { return Object.values(shortcuts).filter(s => s.category === category); } /** * Get all shortcuts grouped by category */ export function getShortcutsGrouped(): Record { const grouped: Record = { global: [], navigation: [], bogforing: [], faktura: [], bank: [], kunder: [], produkter: [], }; Object.values(shortcuts).forEach(shortcut => { grouped[shortcut.category].push(shortcut); }); return grouped; } /** * Format shortcut keys for display * Converts 'mod+k' to '⌘K' on Mac or 'Ctrl+K' on Windows */ export function formatShortcut(keys: string): string { return keys .split(' ') .map(part => part .replace(/mod/g, modifierKey) .replace(/shift/g, shiftKey) .replace(/alt/g, altKey) .replace(/\+/g, '') .toUpperCase() ) .join(' '); } /** * Format shortcut for tooltip display * Returns formatted string like "⌘K" or "Ctrl+K" */ export function formatShortcutForTooltip(shortcutId: string): string | null { const shortcut = shortcuts[shortcutId]; if (!shortcut) return null; return formatShortcut(shortcut.keys); } /** * Category display names in Danish */ export const categoryNames: Record = { global: 'Globale', navigation: 'Navigation', bogforing: 'Bogføring', faktura: 'Fakturering', bank: 'Bank', kunder: 'Kunder', produkter: 'Produkter', }; /** * Navigation routes mapping */ export const navigationRoutes: Record = { goToDashboard: '/', goToKassekladde: '/kassekladde', goToKontooversigt: '/kontooversigt', goToFakturaer: '/fakturaer', goToKreditnotaer: '/kreditnotaer', goToBankafstemning: '/bankafstemning', goToKunder: '/kunder', goToProdukter: '/produkter', goToMomsindberetning: '/momsindberetning', goToIndstillinger: '/indstillinger', }; /** * Command palette items */ export interface CommandItem { id: string; label: string; description?: string; icon?: string; shortcut?: string; category: 'navigation' | 'action' | 'recent'; action: () => void; }