feat: integrate global keyboard shortcuts across multiple components

- Added `KeyboardShortcutsProvider` to `RootLayout` for centralized keyboard shortcut management.
- Implemented `useGlobalKeyboardShortcuts` in `DailyPageClient`, `KanbanPageClient`, and `HomePageClient` to enhance navigation and task management with keyboard shortcuts.
- Updated `KeyboardShortcuts` component to render a modal for displaying available shortcuts, improving user accessibility.
- Enhanced `Header` component with buttons to open the keyboard shortcuts modal, streamlining user interaction.
This commit is contained in:
Julien Froidefond
2025-09-29 17:29:11 +02:00
parent c1a14f9196
commit 749f69680b
10 changed files with 487 additions and 8 deletions

View File

@@ -0,0 +1,102 @@
'use client';
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
interface KeyboardShortcutsActions {
onCreateTask?: () => void;
onToggleFilters?: () => void;
onToggleCompactView?: () => void;
onToggleSwimlanes?: () => void;
onNavigatePrevious?: () => void;
onNavigateNext?: () => void;
onGoToToday?: () => void;
onRefresh?: () => void;
onExport?: () => void;
onShowAnalytics?: () => void;
onSave?: () => void;
onBackup?: () => void;
onOpenSearch?: () => void;
}
export function useGlobalKeyboardShortcuts(actions: KeyboardShortcutsActions = {}) {
const pathname = usePathname();
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// Éviter les raccourcis si on est dans un input/textarea
const target = event.target as HTMLElement;
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.contentEditable === 'true') {
// Permettre seulement certains raccourcis dans les inputs
if (event.key === 'Escape') {
// Esc pour fermer les modales même dans les inputs
return;
}
// Ignorer les autres raccourcis dans les inputs
return;
}
// Cmd+K - Ouvrir la recherche rapide
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
event.preventDefault();
actions.onOpenSearch?.();
return;
}
// Cmd+N - Créer une nouvelle tâche/élément
if ((event.metaKey || event.ctrlKey) && event.key === 'n') {
event.preventDefault();
actions.onCreateTask?.();
return;
}
// Cmd+F - Ouvrir les filtres (Kanban)
if ((event.metaKey || event.ctrlKey) && event.key === 'f') {
event.preventDefault();
actions.onToggleFilters?.();
return;
}
// Cmd+S - Basculer les swimlanes (Kanban)
if ((event.metaKey || event.ctrlKey) && event.key === 's') {
event.preventDefault();
actions.onToggleSwimlanes?.();
return;
}
// Space - Basculer la vue compacte (Kanban)
if (event.key === ' ' && pathname === '/kanban') {
event.preventDefault();
actions.onToggleCompactView?.();
return;
}
// Cmd+T - Aller à aujourd'hui/cette semaine
if ((event.metaKey || event.ctrlKey) && event.key === 't') {
event.preventDefault();
actions.onGoToToday?.();
return;
}
// Flèches gauche/droite - Navigation
if (event.key === 'ArrowLeft') {
event.preventDefault();
actions.onNavigatePrevious?.();
return;
}
if (event.key === 'ArrowRight') {
event.preventDefault();
actions.onNavigateNext?.();
return;
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [pathname, actions]);
}

View File

@@ -8,7 +8,7 @@ export function useKeyboardShortcuts() {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
// Cmd + T pour basculer entre light et le thème dark préféré
// Cmd + Shift + D pour basculer entre light et le thème dark préféré
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'D') {
event.preventDefault();
toggleTheme();